当前位置:  技术问答>linux和unix

诡异的extern问题。

    来源: 互联网  发布时间:2016-08-07

    本文导语:  本帖最后由 sunnyqboy 于 2009-07-30 18:55:11 编辑 今天本来想研究一下extern的具体作用,因为一直很模糊。写了一个测试程序。发现了一个奇怪的问题。 aa.c int i; main() {    //extern int i;    printf("%dn", i); } bb.c int i =...

本帖最后由 sunnyqboy 于 2009-07-30 18:55:11 编辑
今天本来想研究一下extern的具体作用,因为一直很模糊。写了一个测试程序。发现了一个奇怪的问题。
aa.c


int i;
main()
{
   //extern int i;
   printf("%dn", i);
}


bb.c

int i = 10;


编译命令: cc –o aa aa.c bb.c
结果:10

使用全局变量i,和在main函数里面使用extern int i结果一样都是10。

请问为什么将i设为全局变量只要联合编译就自动extern了? 

2、另外,我们经常在头文件中定义
#define EXTERN extern

EXTERN int i;来说明某一个变量被外部引用。

在某些文件中使用
#define EXTERN
然后在引入定义i的头文件的时候说明其不是从外部引用?(我这块比较混乱,谁能讲一下?)
但是按照上面程序测试的做法,岂不是所有的都是extern?这样#define EXTERN不就没有用了?我很郁闷,请大家指点。



|
总结一下吧:

extern int i;
——外部引用声明;声明引用一个名字为i的整形变量;

int i;
——全局变量定义;默认具有外部连接性,可从另一个文件中通过extern声明来引用。
注意做全局变量时它将被默认初始化成0。
(当然,在本文件内部,定义本身同时也是声明。不管是定义过还是仅仅声明过,都能使名字变得“可见”。)

extern int i = 10;
——注意带初始化式的extern,这个是定义,而不仅仅是声明。

static int i;
static int i = 10;
——静态变量定义。
static全局变量是具有内连接属性,另一个文件用extern引用也引用不到;注意第一个会被默认初始化成0。

const int i = 10;
——在C++语言中,const全局变量是个特例,它默认具有内部连接性的,而不像一般全局变量那样默认是外部连接性的。因此这种可以像宏一样直接扔到头件中,即使被多个文件include也不会造成符号重定义错误。

|
其实用 nm 可以看看

// a.c

int i; // 0000000000000004 C i

// b.c

int i = 10; // 0000000000000000 D i



 "C" The  symbol  is common. 

 Common symbols are uninitialized data.  When linking, multiple
common symbols may appear with the same name.  If the symbol is
defined  anywhere,  the common symbols are treated as undefined references.

"D" The symbol is in the initialized data section.


如果改为

// a.c
int i = 10;

// b.c
int i = 10;


那就会出现重复定义的错误了

|

用nm可以帮助理解三种不同的形式的变量说明:

int x;          /* C (Common) 声明(可能同时也定义)变量, 到了链接阶段, */
                /* 1. 如果没在其他模块发现同名(D)符号,作为未初始化的全局变量, 放在BSS */
                /* 2. 如果有在其他模块发现同名(D)符号,作为已初始化的全局变量, 放在数据段 */
int y = 1;      /* D (Data)   定义变量,作为已初始化的全局变量, 放在数据段 */
extern int z;  /* U (Undefined), 声明变量, 到了链接阶段 */
                /* 1. 如果在其他模块有且仅有一个类型(D)的同名符号,将此符号解析到此 */
                /*    (D)符号,作为已初始化的全局变量, 放在数据段 */
                /* 2. 如果在其他模块有两个或更多的类型(D)的同名符号,*/
                /*    报告“重复定义”,链接失败 */
                /* 3. 如果在其他模块未发现类型(D)的同名符号,但是至少有一个类型(C) */
                /*    的同名符号, 将此符号解析到此(C)符号上, 
                /*    作为未初始化的全局变量, 放在BSS */

简单来说,
int x;         可以在多个模块,
int x = 1;     只能在一个模块
extern int x;  可以在多个模块, 且至少还需要在其他模块有一个 int x; 或 int x = 1;

|
nm基本用法命令

  nm用来列出目标文件的符号清单。下面是nm命令的格式:

  nm [-a|--debug-syms] [-g|--extern-only] [-B][-C|--demangle] [-D|--dynamic] [-s|--print-armap][-o|--print-file-name] [-n|--numeric-sort][-p|--no-sort] [-r|--reverse-sort] [--size-sort][-u|--undefined-only] [-l|--line-numbers] [--help][--version] [-t radix|--radix=radix][-P|--portability] [-f format|--format=format][--target=bfdname] [objfile...]

  如果没有为nm命令指出目标文件,则nm假定目标文件是a.out。下面列出该命令的任选项,大部分支持"-"开头的短格式和"—"开头的长格式。
-A、-o或--print-file-name:在找到的各个符号的名字前加上文件名,而不是在此文件的所有符号前只出现文件名一次。 

例如nm libtest.a的输出如下:
CPThread.o:
00000068 T Main__8CPThreadPv
00000038 T Start__8CPThread
00000014 T _._8CPThread
00000000 T __8CPThread
00000000 ? __FRAME_BEGIN__
.......................................

则nm -A 的输出如下:
libtest.a:CPThread.o:00000068 T Main__8CPThreadPv
libtest.a:CPThread.o:00000038 T Start__8CPThread
libtest.a:CPThread.o:00000014 T _._8CPThread
libtest.a:CPThread.o:00000000 T __8CPThread
libtest.a:CPThread.o:00000000 ? __FRAME_BEGIN__
..................................................................
-a或--debug-syms:显示调试符号。 
-B:等同于--format=bsd,用来兼容MIPS的nm。 
-C或--demangle:将低级符号名解码(demangle)成用户级名字。这样可以使得C++函数名具有可读性。 
-D或--dynamic:显示动态符号。该任选项仅对于动态目标(例如特定类型的共享库)有意义。 
-f format:使用format格式输出。format可以选取bsd、sysv或posix,该选项在GNU的nm中有用。默认为bsd。 
-g或--extern-only:仅显示外部符号。 
-n、-v或--numeric-sort:按符号对应地址的顺序排序,而非按符号名的字符顺序。 
-p或--no-sort:按目标文件中遇到的符号顺序显示,不排序。 
-P或--portability:使用POSIX.2标准输出格式代替默认的输出格式。等同于使用任选项-f posix。 
-s或--print-armap:当列出库中成员的符号时,包含索引。索引的内容包含:哪些模块包含哪些名字的映射。 
-r或--reverse-sort:反转排序的顺序(例如,升序变为降序)。 
--size-sort:按大小排列符号顺序。该大小是按照一个符号的值与它下一个符号的值进行计算的。 
-t radix或--radix=radix:使用radix进制显示符号值。radix只能为"d"表示十进制、"o"表示八进制或"x"表示十六进制。 
--target=bfdname:指定一个目标代码的格式,而非使用系统的默认格式。 
-u或--undefined-only:仅显示没有定义的符号(那些外部符号)。 
-l或--line-numbers:对每个符号,使用调试信息来试图找到文件名和行号。对于已定义的符号,查找符号地址的行号。对于未定义符号,查找指向符号重定位入口的行号。如果可以找到行号信息,显示在符号信息之后。 
-V或--version:显示nm的版本号。 
--help:显示nm的任选项。

http://dev.csdn.net/article/69/69405.shtm

    
 
 
 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • java命名空间javax.xml.stream类xmlinputfactory成员方法: is_supporting_external_entities定义参考
  • 请问只有变量只有extern 形式 但是删去extern 之后 会有 multiple defination error
  • mod_auth_external
  • extern 的疑问:
  • 关于QT的extern,如何引进一个结构体
  • 关于外部函数extern func的用法疑问
  • 网卡external loopback测试程序
  • 请高手帮我解释这句话extern __FAR__ GT_Config *GT;
  • error LNK2001: unresolved external symbol 求助
  • 请教,extern使用出错(很小的程序)
  • c语言中static和extern的用法详细解析
  • Linux下使用extern如何写makefile
  • 关于error LNK2001: unresolved external symbol 的一个发现
  • 从汇编看c++中extern关键字的使用
  • C/C++中extern "C" 的作用分析
  • 提示出现unresolved external symbol _main的解决方法
  • 操作系统 iis7站长之家
  • 浅谈C/C++中的static与extern关键字的使用详解
  • 深入理解C语言 static、extern与指针函数
  • extern char** environ这个变量是从哪来的??
  • 急:error LNK2001: unresolved external symbol _rindex


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3