哪位牛人来给解释解释extern与static

时间:2021-12-16 00:42:26
#include <stdio.h>
#ifdef __cplusplus
extern "C"{
#endif
extern int my_test_func(int);
void test_my_test_func(void)
{
int int_ptr;
int_ptr=my_test_func(3);
}
static int my_test_func(int a)
{
return a;
}
int main(void)
{
test_my_test_func();
return 0;
}
#ifdef __cplusplus
}
#endif
如上,通过编译,还能运行。用的是VC6.0,注意,前面的函数原型是extern的,后面的定义是static的。明明矛盾了,为什么可以通过编译?可以认为是编译器的一个BUG吗?请不懂得不要瞎说,免得误人子弟。谢谢。

24 个解决方案

#1


extern 是外部声明变量,也用作c++引用C语言库函数。
static 是静态变量描述符。

#2


vc6编译器的原因,用MinGW 编译不过

#3


个人感觉,extern 只是申明了这个函数可能在其它地方定义,只是一个申明,对编译器的一个提示,告诉编译器这个函数可能在其它地方定义。并没有强制这个函数被引用的范围,static 在这里就是限定了该函数被引用的范围。

#4


引用 2 楼 coverallwangp 的回复:
vc6编译器的原因,用MinGW 编译不过

谢谢测试,这下心里踏实了。

#5


$ gcc test.c
test.c:11: error: static declaration of 'my_test_func' follows non-static declaration
test.c:5: note: previous declaration of 'my_test_func' was here

#6


全局变量,局部变量,静态全局变量,静态局部变量,静态函数
   在一个.cpp文件中定义的全局变量,在所有的cpp文件中都是可见的。其作用域是全局和全时间的。局部可以重新定义和全局变量同名的变量来屏蔽掉全局变量,局部变量的生存期是其所在的大括号。
   静态全局变量是在静态内存区域分配的空间,其作用域是全时间但仅仅在定义它的cpp文件中有效,在其他的源文件中是不可见的。静态全局变量的值一旦被修改,在其生存期内是不会改变的。静态局部变量也是在静态内存区域分配的内存空间,其作用域是全时间的但仅仅在其定义的函数中可见,其他函数和cpp文件中都不可见。
   静态函数,仅仅在本cpp文件中声明,定义和使用的函数应该定义为静态函数,防止其他cpp文件调用。其他普通函数应该在头文件中声明,在头文件对应的cpp文件中定义。使用时包含对应的头文件就可以了。

#7


引用 3 楼 allen1986 的回复:
个人感觉,extern 只是申明了这个函数可能在其它地方定义,只是一个申明,对编译器的一个提示,告诉编译器这个函数可能在其它地方定义。并没有强制这个函数被引用的范围,static 在这里就是限定了该函数被引用的范围。

在C里面,extern和static是存储类区分符,可以看成是一对冤家。如果一个函数的说明或原型与定义出现在同一个文件中。那么必须是一致的,要么都是static,要么都是extern的。C++的不太清楚。

#8


恩,一个扩展,一个静态

#9


  这肯定有问题呀  gcc下编译错误

#10


珍爱生命,远离VC6

#11


d:\temp\test\main.cpp(12) : warning C4211: nonstandard extension used : redefined extern to static

LZ你没看警告吧

#12


VC用的编译器查的松已经是众所周知了

#13


C:\Documents and Settings\clerk\My Documents\test\test.cpp||In function `int my_test_func(int)':|
C:\Documents and Settings\clerk\My Documents\test\test.cpp|12|error: `int my_test_func(int)' was declared `extern' and later `static'|
C:\Documents and Settings\clerk\My Documents\test\test.cpp|5|error: previous declaration of `int my_test_func(int)'|
||=== Build finished: 2 errors, 0 warnings ===|

#14


这其实不能简单是说编译器的问题,应该从ANSI C标准上来说明问题。
1、标准C语言要求函数的第一个声明就指定为外部函数或是静态函数,所以,首先,这种属于很不好的编程风格。

2、标准C语言没有明确地禁止“先extern 后static的风格”,但也没有指定其含义,所以肯定不同的C实现会有不同的实现方式。

3、使用VC++ 2008编译,将Warn level 设置为Level 4,会提示一个警告:
warning C4211: nonstandard extension used : redefined extern to static
你可以设置将警告也设置成错误,来达到编译完全不通过的目的。

使用code::blocks 8.02版,使用GNU GCC 编译,也是给出warning:
warning: static declaration of 'my_test_func' follows non-static declaration|
warning: previous declaration of 'my_test_func' was here
||=== Build finished: 0 errors, 2 warnings ===|

4、我是在Windows平台下进行的测试,身边没有VC6,所以真的VC6有问题,MS其实也做啦改进。

#15


xuexi~

#16


引用 14 楼 wissup 的回复:
这其实不能简单是说编译器的问题,应该从ANSI C标准上来说明问题。
 1、标准C语言要求函数的第一个声明就指定为外部函数或是静态函数,所以,首先,这种属于很不好的编程风格。

 2、标准C语言没有明确地禁止“先extern 后static的风格”,但也没有指定其含义,所以肯定不同的C实现会有不同的实现方式。

 3、使用VC++ 2008编译,将Warn level 设置为Level 4,会提示一个警告:
 warning C4211: nonstandard extension used : redefined extern to static
 你可以设置将警告也设置成错误,来达到编译完全不通过的目的。

 使用code::blocks 8.02版,使用GNU GCC 编译,也是给出warning:
 warning: static declaration of 'my_test_func' follows non-static declaration|
 warning: previous declaration of 'my_test_func' was here
 ||=== Build finished: 0 errors, 2 warnings ===|

 4、我是在Windows平台下进行的测试,身边没有VC6,所以真的VC6有问题,MS其实也做啦改进。

郁闷啊,我的VC6设置levl4还是没警告。

#17


我还是别说话了。免得误人子弟。

#18


不管编译器是怎么实现的

但是楼主这样做
先 extern 然后  static

几乎就是在摧残编译器

尽管C语法上的确存在“作用域”一说
但是忘记它吧
没有任何人在实际的工作中来利用这1点
这几乎就是在考验编译器,
考验阅读你代码的人
考验后来的维护人员

#19


一、 你的代码都是在同一个文件中,重载时,文件内的函数优先级最高。
所以内部static函数会覆盖 extern的函数。如果当前文件内没有相应的函数,才会使用extern声明,如果你的工程中没有my_test_func函数,那么就会产生一个link错误。

二、 你的声明和调用书写顺序为:
extern func();
...
call func();
....
static func(){
}

所以在调用处会使用extern func();extern的含义是全局,当前文件也在全局范围之内,所以能查找到static func()。static只是限制函数只能在本文件内调用。所以不会产生错误。

#20


学习了

#21


6楼说得很清楚了
顶18楼

#22


extern是在生命变量,static是在定义变量,static在c++必须要给初始值,java中可以不给初始值,毕竟java是在变量被使用时才给资源。vc6对c89的标准支持不好,使用模板经常出bug,推荐用vs2005或vs2008的c++编译器,这个东西号称支持标准98%,我目前没发现bug。不过一般小文件直接g++好了。方便。嘿嘿

#23


在看翻译版的ANSI C标准,发现在这个地方前后说的也不一致。不知道是翻译的错误。还是标准自己规定也不严格?
讲到的一个词条为:函数说明符,在函数体词条前面。
还有一个是在哪个词条忘记了。懒得去前面查了。再说是翻译的。也不一定准。

#24



#include <iostream>
using namespace std;


extern int my_test_func(int); 
static int my_test_func(int a) 

return a; 



#define MAX(a, b)    (a > b ? a : b)

void main(int argc, char **argv)
{
    int max1 = MAX(2 + 3, 1 + 9);
int max2 = MAX(2 + 3, 9 + 1);
int max3 = MAX(9/3, 1 + 9);

my_test_func(5);

cout << max1 << "\t" << max2 << "\t" <<max3 << endl;
}


真的没有错误,连警告都没有,咋回事?

#1


extern 是外部声明变量,也用作c++引用C语言库函数。
static 是静态变量描述符。

#2


vc6编译器的原因,用MinGW 编译不过

#3


个人感觉,extern 只是申明了这个函数可能在其它地方定义,只是一个申明,对编译器的一个提示,告诉编译器这个函数可能在其它地方定义。并没有强制这个函数被引用的范围,static 在这里就是限定了该函数被引用的范围。

#4


引用 2 楼 coverallwangp 的回复:
vc6编译器的原因,用MinGW 编译不过

谢谢测试,这下心里踏实了。

#5


$ gcc test.c
test.c:11: error: static declaration of 'my_test_func' follows non-static declaration
test.c:5: note: previous declaration of 'my_test_func' was here

#6


全局变量,局部变量,静态全局变量,静态局部变量,静态函数
   在一个.cpp文件中定义的全局变量,在所有的cpp文件中都是可见的。其作用域是全局和全时间的。局部可以重新定义和全局变量同名的变量来屏蔽掉全局变量,局部变量的生存期是其所在的大括号。
   静态全局变量是在静态内存区域分配的空间,其作用域是全时间但仅仅在定义它的cpp文件中有效,在其他的源文件中是不可见的。静态全局变量的值一旦被修改,在其生存期内是不会改变的。静态局部变量也是在静态内存区域分配的内存空间,其作用域是全时间的但仅仅在其定义的函数中可见,其他函数和cpp文件中都不可见。
   静态函数,仅仅在本cpp文件中声明,定义和使用的函数应该定义为静态函数,防止其他cpp文件调用。其他普通函数应该在头文件中声明,在头文件对应的cpp文件中定义。使用时包含对应的头文件就可以了。

#7


引用 3 楼 allen1986 的回复:
个人感觉,extern 只是申明了这个函数可能在其它地方定义,只是一个申明,对编译器的一个提示,告诉编译器这个函数可能在其它地方定义。并没有强制这个函数被引用的范围,static 在这里就是限定了该函数被引用的范围。

在C里面,extern和static是存储类区分符,可以看成是一对冤家。如果一个函数的说明或原型与定义出现在同一个文件中。那么必须是一致的,要么都是static,要么都是extern的。C++的不太清楚。

#8


恩,一个扩展,一个静态

#9


  这肯定有问题呀  gcc下编译错误

#10


珍爱生命,远离VC6

#11


d:\temp\test\main.cpp(12) : warning C4211: nonstandard extension used : redefined extern to static

LZ你没看警告吧

#12


VC用的编译器查的松已经是众所周知了

#13


C:\Documents and Settings\clerk\My Documents\test\test.cpp||In function `int my_test_func(int)':|
C:\Documents and Settings\clerk\My Documents\test\test.cpp|12|error: `int my_test_func(int)' was declared `extern' and later `static'|
C:\Documents and Settings\clerk\My Documents\test\test.cpp|5|error: previous declaration of `int my_test_func(int)'|
||=== Build finished: 2 errors, 0 warnings ===|

#14


这其实不能简单是说编译器的问题,应该从ANSI C标准上来说明问题。
1、标准C语言要求函数的第一个声明就指定为外部函数或是静态函数,所以,首先,这种属于很不好的编程风格。

2、标准C语言没有明确地禁止“先extern 后static的风格”,但也没有指定其含义,所以肯定不同的C实现会有不同的实现方式。

3、使用VC++ 2008编译,将Warn level 设置为Level 4,会提示一个警告:
warning C4211: nonstandard extension used : redefined extern to static
你可以设置将警告也设置成错误,来达到编译完全不通过的目的。

使用code::blocks 8.02版,使用GNU GCC 编译,也是给出warning:
warning: static declaration of 'my_test_func' follows non-static declaration|
warning: previous declaration of 'my_test_func' was here
||=== Build finished: 0 errors, 2 warnings ===|

4、我是在Windows平台下进行的测试,身边没有VC6,所以真的VC6有问题,MS其实也做啦改进。

#15


xuexi~

#16


引用 14 楼 wissup 的回复:
这其实不能简单是说编译器的问题,应该从ANSI C标准上来说明问题。
 1、标准C语言要求函数的第一个声明就指定为外部函数或是静态函数,所以,首先,这种属于很不好的编程风格。

 2、标准C语言没有明确地禁止“先extern 后static的风格”,但也没有指定其含义,所以肯定不同的C实现会有不同的实现方式。

 3、使用VC++ 2008编译,将Warn level 设置为Level 4,会提示一个警告:
 warning C4211: nonstandard extension used : redefined extern to static
 你可以设置将警告也设置成错误,来达到编译完全不通过的目的。

 使用code::blocks 8.02版,使用GNU GCC 编译,也是给出warning:
 warning: static declaration of 'my_test_func' follows non-static declaration|
 warning: previous declaration of 'my_test_func' was here
 ||=== Build finished: 0 errors, 2 warnings ===|

 4、我是在Windows平台下进行的测试,身边没有VC6,所以真的VC6有问题,MS其实也做啦改进。

郁闷啊,我的VC6设置levl4还是没警告。

#17


我还是别说话了。免得误人子弟。

#18


不管编译器是怎么实现的

但是楼主这样做
先 extern 然后  static

几乎就是在摧残编译器

尽管C语法上的确存在“作用域”一说
但是忘记它吧
没有任何人在实际的工作中来利用这1点
这几乎就是在考验编译器,
考验阅读你代码的人
考验后来的维护人员

#19


一、 你的代码都是在同一个文件中,重载时,文件内的函数优先级最高。
所以内部static函数会覆盖 extern的函数。如果当前文件内没有相应的函数,才会使用extern声明,如果你的工程中没有my_test_func函数,那么就会产生一个link错误。

二、 你的声明和调用书写顺序为:
extern func();
...
call func();
....
static func(){
}

所以在调用处会使用extern func();extern的含义是全局,当前文件也在全局范围之内,所以能查找到static func()。static只是限制函数只能在本文件内调用。所以不会产生错误。

#20


学习了

#21


6楼说得很清楚了
顶18楼

#22


extern是在生命变量,static是在定义变量,static在c++必须要给初始值,java中可以不给初始值,毕竟java是在变量被使用时才给资源。vc6对c89的标准支持不好,使用模板经常出bug,推荐用vs2005或vs2008的c++编译器,这个东西号称支持标准98%,我目前没发现bug。不过一般小文件直接g++好了。方便。嘿嘿

#23


在看翻译版的ANSI C标准,发现在这个地方前后说的也不一致。不知道是翻译的错误。还是标准自己规定也不严格?
讲到的一个词条为:函数说明符,在函数体词条前面。
还有一个是在哪个词条忘记了。懒得去前面查了。再说是翻译的。也不一定准。

#24



#include <iostream>
using namespace std;


extern int my_test_func(int); 
static int my_test_func(int a) 

return a; 



#define MAX(a, b)    (a > b ? a : b)

void main(int argc, char **argv)
{
    int max1 = MAX(2 + 3, 1 + 9);
int max2 = MAX(2 + 3, 9 + 1);
int max3 = MAX(9/3, 1 + 9);

my_test_func(5);

cout << max1 << "\t" << max2 << "\t" <<max3 << endl;
}


真的没有错误,连警告都没有,咋回事?