【问题标题】:Redeclaration of global variable vs local variable全局变量与局部变量的重新声明
【发布时间】:2014-02-12 02:26:07
【问题描述】:

当我编译下面的代码时

#include<stdio.h>

int main()
{
  int a;
  int a = 10;
  printf("a is %d \n",a);
  return 0;
}

我收到一个错误:

test3.c: In function ‘main’:
test3.c:6:5: error: redeclaration of ‘a’ with no linkage
test3.c:5:5: note: previous declaration of ‘a’ was here

但如果我将变量设为全局变量,那么它就可以正常工作。

#include<stdio.h>

int a;
int a = 10;
int main()
{
  printf("a is %d \n",a);
  return 0;
}

为什么声明同一个全局变量两次不是错误,而对局部变量这样做却是错误?

【问题讨论】:

  • this question答案的最后一部分。
  • @downvoters 愿意发表评论。如果您对重复投反对票,请投赞成票,不要投反对票。

标签: c declaration definition redefinition one-definition-rule


【解决方案1】:

在 C 语言中,int a; 在文件范围内的声明是一个声明和一个暂定定义。您可以拥有任意数量的暂定定义,只要它们彼此匹配即可。

如果定义(带有初始化器)出现在翻译单元的末尾之前,则变量将被初始化为该值。有多个初始化值是编译器错误。

如果到达翻译单元的末尾,并且没有找到非暂定定义,则变量将被初始化为零。

以上不适用于局部变量。这里的声明也可以作为定义,多于一个会导致错误。

【讨论】:

  • 在局部变量的情况下,由于声明和定义相同,为什么会出现重新声明错误,为什么没有重新定义错误?如果是局部变量,我们实际上是在定义,因此错误应该是重新定义的吧?
  • 虽然正确,但并没有真正回答问题。真正的原因是您只能在 大多数 范围内声明一个名称。例外是文件范围 - 只要它们兼容,您可以在文件范围内拥有任意数量的名称声明。这与任何定义无关。
【解决方案2】:

我能想到的另一个原因是未初始化的全局变量存储在 BSS(块结构化段)中,而初始化的全局变量存储在数据段中。

我猜测存在某种名称空间解析,当发生冲突时,数据段中的变量会覆盖块结构化段中的变量。

如果你要声明

int a =5 int a = 10

在全局范围内(都在数据段中)会出现预期的冲突。

【讨论】:

  • 根据您的解释,a 应该有两份副本,在 bss 和 data 段中各一份(无论如何都是实现细节,标准中从未提及)。
【解决方案3】:

C 程序中不能有两个同名的全局变量。 C 可能通过暂定定义规则允许同一文件范围内的多个定义,但无论如何所有定义都将引用同一个变量。

局部变量

在 C 中,多个局部变量不会“合并”为一个。

所有具有相同名称的局部变量将引用不同的 int 大小的内存。

 #include<stdio.h>

 int main()
 {
  int a;
  int a = 10;
  printf("a is %d \n",a);  
  return 0;
 }

因此,当将内存分配给同一变量的重新声明时,它会给出错误。

全局变量

在 C 中,多个全局变量被“合并”为一个。所以你确实只有一个全局变量,多次声明。这可以追溯到 C 中不需要(或可能不存在 - 不太确定)外部的时代。

换句话说,所有同名的全局变量都将被转换为一个变量——所以你的

#include<stdio.h>

int a;
int a = 10;
int main()
{
printf("a is %d \n",a);
return 0;
}

将引用相同的 int 大小的内存。

【讨论】:

  • 如果语句在全局范围内是int a=5;int a=10;,那么最终值是多少?原来是编译错误!
  • @Vaibhav 您的“合并”概念的任何规范。我第一次听说这个。!
  • @nitish712 你可以有多个声明,但只有一个定义。
  • @VaibhavJain 那么对于我的问题,为什么它会给我一个编译错误?也许你应该说declaration 而不是@tesseract 指出的definition。见this
  • 您的答案中的前两句话(奇怪地格式化为代码)具有误导性。您说允许多个定义,这是不正确的。假设变量具有外部链接,则不允许跨多个翻译单元进行多个定义,更不用说同一个。现在,在同一个翻译单元中允许多个 tentative 定义(在大多数编译器上跨多个),但是在解释 tentative 和 non-tentative 定义之间的区别时,您确实需要明确说明您是哪一个'正在谈论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多