C中变量重复声明

机缘巧合在网上看到在C中用extern声明函数和不用extern声明函数是没有区别的,但却没人提用变量用extern声明有没有区别,自己稍微研究一下,发现它们还是有区别的。

刚开始找到了The GNU C Reference Manual中一段相关的描述:

Uninitialized variables that are declared as extern are given default values of 0, 0.0, or
NULL, depending on the type. Uninitialized variables that are declared as auto or register
(including the default usage of auto) are left uninitialized, and hence should not be assumed
to hold any particular value.
extern is useful for declaring variables that you want to be visible to all source files
that are linked into your project. You cannot initialize a variable in an extern declaration,
as no space is actually allocated during the declaration. You must make both an extern
declaration (typically in a header file that is included by the other source files which need to
access the variable) and a non-extern declaration which is where space is actually allocated
to store the variable. The extern declaration may be repeated multiple times.

但再阅读更多的资料后发现其中有些不对的地方。。。也是醉了。

首先上面2段中说extern变量是不会被分配空间的,但又说未初始化的extern变量会被分配默认值,自相矛盾。然后在gcc实现中,extern变量是可以被初始化的,只不过gcc会报warning:

init_test.c:3:12: warning: ‘a’ initialized and declared ‘extern’
 extern int a = 10;

根据上面2段的描述中我们可以看到extern变量是可以被多次声明的,那么非extern变量(不包括auto,register这样的)呢,文中没说是不是就以为着不能重复声明呢?自己实验一下发现编译一个重复声明变量的文件是可以通过的。

1 int a;
2 int a;

一个就包含上述2行的文件是可以编译的,原因在C标准中定义了,以下摘自C99:

A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier static, constitutes a
tentative definition. If a translation unit contains one or more tentative definitions for an
identifier, and the translation unit contains no external definition for that identifier, then
the behavior is exactly as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation unit, with an initializer
equal to 0.

所以假如在像下面这样写,是不能通过编译的:

1 int
2 main (void)
3 {
4     int a;
5     int a;
6 }

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

时间: 2024-08-10 03:13:51

C中变量重复声明的相关文章

【repost】 JS变量重复声明以及忽略var 声明的问题及其背后的原理

JS的容错率很高,一些其他语言常见的小错误JS都能大度得包容,比如给一个方法传入超出预计的参数.在声明变量之前使用该变量(变量的声明提升解决了这个问题)等等,这里我们就要解剖一下JS变量重复声明以及当我们忽略var使用 a=2来声明变量时a为全局变量的问题: [javascript] view plain copy //第一段代码 var a = 2; var a = 3; alert(a);//3 //第二段代码 <span style="font-size:18px;">

js中变量的声明

大家都知道js中变量的声明是要提前的,以下有4个例子: 1.if(!"t" in window){ var t = 1; } alert(t);答案是undefined,为什么呢,就是因为变量声明提前了,所以t是在window对象里面的,但是没有走下面的判断,所以并没有赋值,答案就是undefine 2.var num = 100; function fn(){ var num = num + 1; return num; } falert(n());答案依然是NaN,因为在函数体内部

c#中变量的声明和初始化

int i; string text; for(i = 0 ; i < 10; i++) { text = "Line"+Convert.ToString(i); Console.WriteLine("{0}",text); } Console.WriteLine("Last text in loop :{0}",text); 这段代码编译也会失败,变量text必须在使用前进行声明和初始化,而text是在循环中初始化的,赋给text的值在循

【C++】C++中变量的声明与定义的区别

声明(declaration):意味着告诉编译器关于变量名称.变量类型.变量大小.函数名称.结构名称.大小等等信息,并且在声明阶段不会给变量分配任何的内存. 定义(definition):定义就是在变量声明后,给它分配上内存.可以看成“定义 = 声明 + 内存分配”. 例如: #include <iostream> using namespace std; int addtion(int a,int b);//声明 struct product{unsigned int weight;doub

今日新知(关于递归中变量的声明)

在递归函数中用到的变量,要将它声明为局部变量,切记不能声明为全局变量. 如下面归并排序中的变量k. 1 #include<iostream> 2 3 using namespace std; 4 5 const int N = 100010; 6 7 int a[N],b[N]; 8 9 int n ; 10 long long res = 0 ; 11 12 void merge_sort(int a[],int l,int r){ 13 14 if(l >= r) return ;

C++变量的声明和定义 终于搞明白了

1.变量的定义:变量的定义用于为变量分配存储空间,还可以为变量指定初始值.在一个程序中,变量有且仅有一个定义. 2.变量的声明:用于向程序表明变量的类型和名字.程序中变量可以声明多次,但只能定义一次. 3.两者联系与区别: (1)定义也是声明,因为当定义变量时我们也向程序表明了它的类型和名字: (2)但声明不是定义,可以通过使用extern关键字声明变量而不定义它.不定义变量的声明包括对象名.对象类型和对象类型前的关键字extern: 例: extern int i://声明但不定义 int i

JavaScript中变量声明有var和没var的区别

本文来论述JavaScript中变量声明有var和没var的区别,关于Js中的变量声明的作用域是以函数为单位,所以我们经常见到避免全局变量污染的方法是 (function(){ ... })(): 在函数内部,有var和没var声明的变量是不一样的.有var声明的是局部变量,没var的,声明的全局变量. 在全局作用域内声明变量时,有var 和没var看起来都一样,我们知道,声明的全局变量,就是window的属性,究竟是否一样,我们通过ECMAScrpit5提供的属性的特性查询方法,来发现之间的区

ES6中6种声明变量的方法

ES5 只有两种声明变量的方法:var命令和function命令. ES6 除了添加let和const命令,还有两种声明变量的方法:import命令和class命令. 所以,ES6 一共有 6 种声明变量的方法. (1) var命令. var a ; //undefined var b = 1; var定义的变量可以修改,如果不初始化会输出undefined,不会报错 var 声明的变量在window上,用let或者const去声明变量,这个变量不会被放到window上 很多语言中都有块级作用域

C#中对于变量的声明和初始化

C#变量初始化是C#强调安全性的另一个例子.简单地说,C#编译器需要用某个初始值对变量进行初始化,之后才能在操作中引用该变量.大多数现代编译器把没有初始化标记为警告,但C#编译器把它当作错误来看待. 1.在C#中,变量的声明格式为: 数据类型   变量名; 2.变量的赋值格式为: 变量名 = 数据; 3.一般情况下,都是先声明后赋值,或者在声明变量的同时就赋初值.然而有些时候在程序的开发设计中,往往忘了要赋初值(即进行初始化),这样就会导致在程序的设计中,会出现意想不到的错误. 解释:当我们在声