【问题标题】:Conflicting type and variable naming in CC中的冲突类型和变量命名
【发布时间】:2018-11-27 20:23:28
【问题描述】:

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

这是我演示问题的小代码sn-p:

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

那么,我现在的问题!

似乎错误是由于赋值运算符“=”的左值被误认为是type_ttype_c 之间的乘积而产生的。由于type_c 未知,它解释了错误信息。

但是,为什么我们对左值有这种困惑? type_t 指的是类型而不是变量,这不是很明确吗?

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

【问题讨论】:

  • 确认 MSVC 2017 也重现此行为
  • MSVC 2008 抱怨 ... 错误 C2377: 'type_t' : redefinition; typedef 不能用任何其他符号重载....参见“type_t”的声明 ....错误 C2065:“type_c”:未声明的标识符
  • 所以,它一定是 C 标准的一部分……但是,为什么???

标签: c gcc clang


【解决方案1】:

这是预期的正确行为。在 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

这里出现了三个type_t。第一个是 typedef 名称;没问题。第二个是新的变量名;没问题,但它隐藏(阴影)typedef 名称;您不能再在当前代码块中引用类型type_t。第三次出现是指变量;您将整数指针乘以一个未定义的变量(并试图将结果用作左值来接收b 的地址),这在很多层面上都是错误的。

当您颠倒这些行的顺序时,它可以正常工作,因为 type_c 被声明为 type_t * OK;那么type_t 被定义为type_t * 类型的变量,但是在当前块中不能进一步引用type_t 类型(任何这样的引用都是对变量,而不是类型)。

请注意,如果 typedef 在函数内部,您将无法使用 type_t *type_t = &amp;a; 隐藏它。见 C11§6.2.1 Scopes of identifiers

【讨论】:

    猜你喜欢
    • 2017-07-15
    • 2015-10-13
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    • 2018-02-02
    相关资源
    最近更新 更多