I read the Standard N1570 section 6.5.2.2 Function calls
and was confused about the special meaning of the function type that includes prototype. Precisely 6.5.2.2(p6)
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:
— one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is representable in both types;
— both types are pointers to qualified or unqualified versions of a character type or void.
6.5.2.2(p7)
provides a rule of calling function with prototype:
If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type.
Consider the following example:
struct test_arg{
int a;
};
void test_no_prototype(const struct test_arg a){ }
void test_with_prototype(const struct test_arg a);
void test_with_prototype(const struct test_arg a){ }
int main(){
struct test_arg test = {.a = 42};
test_no_prototype(test); //1 UB?
test_with_prototype(test); //2 Fine?
}
I think that 1 is UB because test_no_prototype
does not include prototype and test
has non-qualified version of struct test_arg
, but the argument has type const struct test_arg
which is non-compatible with struct test_arg
because of different qualification.
I think that 2 is fine because test_with_prototype
includes prototype and the simple assignment constraints from 6.5.16.1(p1)
allow assignment of to a variable of qualified struct type from non-qualified version of the same struct.
This seems strange and for now I cannot imagine any reason of why we treat functions with and without prototype differently. Probably I understood the rule incorrectly... If so could you explain what it means?
It means you need to either define your function or else prototype it. In a header file you need to type in something like this… int funtion_name(int parameter_names); and then in a file you need to actually define the function… int function_name(int parameter_name)
A function prototype can always be omitted when: A.A function is defined before it is first invoked.
Function prototype: To declare a function, the prototype function is used. It does not include the function's core, only tells the compiler about the name and return type of the function.
Function prototypes include the function signature, the name of the function, return type and access specifier.
The term prototype does not mean a declaration of a function preceding its definition. It means a declaration of a function that declares the types of its parameters (C 2018 6.2.1 2).
test_no_prototype
has a prototype because void test_no_prototype(const struct test_arg a){ }
declares the type of its parameter, const struct test_arg
.
An example of a declaration without a prototype is void test_no_prototype();
. It is an old style of declaration that should not be used in new code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With