函数调用 n1256 6.5.2.2 p5, p6

Function calls n1256 6.5.2.2 p5, p6

我正在阅读 N1256 6.5.2.2 函数调用。有些部分对我来说很难理解。我用粗体句子或一些关键字在 google 上搜索,但找不到我的问题的直接答案。所以我问我的。

在 6.5.2.2 p5(强调我的)

If the expression that denotes the called function has a type pointer to function returning an object type, the function call expression has the same type as that object type and has the value determined as specified in 6.8.6.4. Otherwise, the function call has type void. If an attempt is made to modify the result of a function call or to access it after the next sequence point, the behavior is undefined.

Q1。加粗的句子是什么意思?有没有办法修改函数调用的结果或在下一个序列点之后访问它?

6.5.2.2 p6的一部分(强调我的)

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined. If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis (, ...) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined. If the function is defined with a type that does not include a prototype, and the types of the arguments after promotion are not compatible with those of the parameters after promotion, the behavior is undefined, except for the following cases: ...

在 6.7 p4,用于兼容类型的定义。

All declarations in the same scope that refer to the same object or function shall specify compatible types.

形式参数不是一个对象,只是一个占位符。 Q2。函数调用的参数和参数可以是同一个对象吗? Q3.为什么标准将提升的参数与参数进行比较?如果有要比较的参数,则不会发生提升,因为只有当编译器不知道被调用者期望的数据类型时才会发生默认参数提升。

(替换之前的答案)

对于问题 3,这似乎是关于表示被调用函数的表达式不包含原型但函数定义包含原型的情况。在这种情况下,参数将受到提升。

void foo1(short s) { // defined with a prototype
    // ...
}

void foo2(int i) { // defined with a prototype
   // ...
}

void bar(void) {
    void (*ptr)(); // no prototype
    char c = 'x';
    short s = 8;
    int i = 1234;
    long l = 12345678;

    ptr = foo1;
    ptr(c); // UB; char promoted to int which is not compatible with short
    ptr(s); // Also UB! short promoted to int which is not compatible with short
    ptr(i); // likewise UB
    // AFAICT there is no way to call foo1 through ptr without UB

    ptr = foo2;
    ptr(c); // OK; char promoted to int which is compatible with int
    ptr(s); // likewise OK
    ptr(i); // likewise OK
    ptr(l); // UB; long is not compatible with int.
}