C

时间:2018-11-27 20:23:28

标签: c gcc clang

我最近偶然发现了一个奇怪的代码构造,该构造导致C编译器进入一种奇怪的状态。我想解释为什么会发生。

这是我的小代码段,演示了该问题:

#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;
}

这是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

或者,用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.

请注意,如果我们按以下方式修改代码,则可以正常编译:

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;
}

所以,我现在的问题!

错误似乎是由于赋值运算符'='的l值被误认为type_ttype_c之间的乘法而产生的。由于type_c未知,因此说明了错误消息。

但是,为什么我们会对l值感到困惑呢? type_t引用类型而不是变量是不是很明确?

我猜这不是一个实现问题,因为gccclang的行为相同。但是,我真的很想知道这个问题的关键。

1 个答案:

答案 0 :(得分:11)

这是预期的正确行为。在C中,有许多namespaces:标签,成员,标签和普通标识符。 typedef名称和变量名称都在普通标识符名称空间中。

您有:

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

这里有3个type_t事件。第一个是typedef名称;没问题。第二个是新的变量名;没问题,但是它隐藏(阴影)了typedef名称;您将无法再在当前代码块中引用类型type_t。第三次出现是指变量;您正在将整数指针与未定义的变量相乘(并尝试将结果用作左值以接收b的地址),这在许多级别上都是错误的。

当您反转这些行的顺序时,它可以正常工作,因为type_c被声明为type_t * OK;然后将type_t定义为类型type_t *的变量,但是在当前块中无法进一步引用类型type_t的引用(任何此类引用都是对变量的引用,而不是对变量的引用。类型)。

请注意,如果typedef位于函数内部,则无法使用type_t *type_t = &a;对其进行阴影处理。参见C11 §6.2.1 Scopes of identifiers