Eric
Eric

Reputation: 97601

In C, is it legal to add `const` only in function definitions, not declarations?

Is adding additional const specifiers to function arguments allowed by the standard, like in the following?

foo.h:

int foo(int x, char * data);

foo.c:

// does this match the prototype?
int foo(const int x, char * const data) {
    // this implementation promises not to change x or move data inside the function
}

GCC accepts it with -std=c99 -Wpedantic -Wall -Werror, but that's not necessarily the same as standard-compliant.

This answer shows that the C++ standard allows this - does the C (99) standard allow this too?


There's another question here and a good answer here for C++

Upvotes: 7

Views: 265

Answers (3)

zwol
zwol

Reputation: 140659

This is explicitly allowed by a special case in the rules for function parameter lists. N1570 §6.7.6.3p131 says:

In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.

But you must also understand that the "unqualified version" of a type like const char * is still const char *, because the type const char * is derived from the type const char, and §6.2.5p26 says

A derived type is not qualified by the qualifiers (if any) of the type from which it is derived.

That means that the declaration

void foo (const int x);

is compatible with the definition

void foo (int x) { ... }

but the declaration

void bar (const char *x)

is not compatible with the definition

void foo (char *x) { ... }

You might be wondering why these rules are the way they are. The short version is that in C, all arguments are always passed by copying the value (but not any data pointed to by the value, if there are pointers involved), so it doesn't matter whether an actual argument is const T; the callee receives it as a regular old T regardless. But if you copy a pointer to constant data, the copy still points to constant data, so it does matter and that qualifier should be preserved.


1 Document N1570 is the closest approximation to the 2011 ISO C standard that is publicly available at no charge.

To the best of my knowledge, these rules have not changed significantly since the original 1989 standard. Pre-C89 "K&R" C didn't have prototypes, nor did it have const, so the entire question would be moot.

Upvotes: 6

Eric
Eric

Reputation: 97601

From the C99 spec, 6.7.5.3.15 Function declarators, this is legal:

If one type has a parameter type list and the other type is specified by a function definition that contains a (possibly empty) identifier list, both shall agree in the number of parameters, and the type of each prototype parameter shall be compatible with the type that results from the application of the default argument promotions to the type of the corresponding identifier. (In the determination of type compatibility and of a composite type, each parameter declared with function or array type is taken as having the adjusted type and each parameter declared with qualified type is taken as having the unqualified version of its declared type.)

Upvotes: 2

Chris Dodd
Chris Dodd

Reputation: 126243

cv-qualifiers on the parameter (and not on the type of the parameter) do not affect the type of the parameter, so do not affect the prototype. Things that don't affect the prototype like this can be different between the declaration and definition with no problem. Similarly, the name of the parameter does not affect the prototype, so can also be different between the declaration and definition.

Now what is confusing is that a const appearing here may be on the parameter or may be on the type of the parameter, depending on exactly where it is. If it is part of the type of the parameter, then it does affect the prototype, so must be consistent between the declaration and definition:

int foo(const int x);   // const on the parameter
int foo(int * const x);  // also const on the parater
int foo(const int *x);  // const in the type, not on the parameter
int foo(int const *x);  // also const in the type

Upvotes: 0

Related Questions