Conflicting type and variable naming in C

  • A+

I recently stumbled on a weird code construct that lead the C compilers to a strange state. I would like to have an explanation why it occurs.

Here is my small code snippet that demonstrate the problem:

#include <stdlib.h>  typedef int type_t;  int main (void) {   int a = 10, b = 100;    type_t *type_t = &a; // We name a variable with type name   type_t *type_c = &b; // We define a variable with type_t    return EXIT_SUCCESS; } 

And here is the error message displayed by gcc:

#> gcc -Wall -Wextra -o sample sample.c  sample.c: In function ‘main’: sample.c:11:11: error: ‘type_c’ undeclared (first use in this function); did you mean ‘type_t’?    type_t *type_c = &b;            ^~~~~~            type_t sample.c:11:11: note: each undeclared identifier is reported only once for each function it appears in 

Or, with clang:

#> clang -Wall -Wextra -o sample sample.c  sample.c:11:11: error: use of undeclared identifier 'type_c'; did you mean 'type_t'?   type_t *type_c = &b;           ^~~~~~           type_t sample.c:10:11: note: 'type_t' declared here   type_t *type_t = &a;           ^ sample.c:11:10: error: invalid operands to binary expression ('type_t *' (aka 'int *') and 'type_t *')   type_t *type_c = &b;   ~~~~~~ ^~~~~~~ 2 errors generated. 

Note that if we modify the code as follow, it compiles fine:

int main (void) {   int a = 10, b = 100;    type_t *type_c = &b; // We define a variable with type_t   type_t *type_t = &a; // We name a variable with type name    return EXIT_SUCCESS; } 

So, my question now!

It seems that the error is produced by the fact that the l-value of the assignation operator '=' is mistaken as a multiplication between type_t and type_c. As type_c is unknown, it explains the error message.

But, why do we have this confusion on an l-value ? Should not it be unambiguous that the type_t refer to the type and not the variable ?

I guess this is not an implementation problem as, both, gcc and clang behave the same. But, I really would like to have the key of this problem.


This is expected and correct behaviour. In C, there are a number of namespaces: labels, members, tags, and ordinary identifiers. A typedef name is in the ordinary identifiers name space, as are variable names.

You have:

type_t *type_t = &a; // We name a variable with type name type_t *type_c = &b; // We define a variable with type_t 

There are three type_t occurrences here. The first is the typedef name; no problem. The second is a new variable name; no problem, but it hides (shadows) the typedef name; you can no longer refer to the type type_t in the current block of code. The third occurrence refers to the variable; you are multiplying an integer pointer by an undefined variable (and trying to use the result as an l-value to receive the address of b), which is wrong on many levels.

When you reverse the order of those lines, it works fine because type_c is declared to be a type_t * OK; then type_t is defined to be a variable of type type_t *, but no further references can be made to the type type_t in the current block (any such reference is to the variable, not the type).

Note that if the typedef was inside the function, you'd not be able to shadow it with type_t *type_t = &a;. See C11 §6.2.1 Scopes of identifiers.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: