概述

本人的原创文章,最先发表在github-Dramalife-note中。转载请注明出处。

Define variable(s) in header file referenced by multiple c files.

(CH:在 被多个c文件引用 的 头文件中定义变量)

If the variable is initialized, GCC will report an error.

(CH:如果这个变量被初始化, GCC会报错)

一般来说,如果需要,变量的声明一边放到头文件中,变量的定义不放到头文件中(尤其是被多个要被编译并链接到同一个可执行文件的源文件引用时)。

本文讨论的来源:

X:变量一定不能放到头文件中定义吗?

D:如果被多个C文件同时引用的话,gcc会报告重复定义变量的错误。

X:但是我在头文件中定义了一个变量,而且这个头文件被多个c文件引用,结果能编过!

D:??

本文源码地址1-github,

本文源码地址1-gitee镜像.

Reason_keywords : stack, heap, nm

总结

简单说明:

在 被多个源文件引用的 头文件 中定义变量,

如果这个变量没有初始化(例:int gb;),那么gcc编译时会把它放到common section,gcc在链接阶段允许有多个同名的common symbol,所以能编译成功;

如果初始化了这个变量(例:int gb = ;),gcc编译时会把变量放到data section或者bss section,gcc在链接时不允许data和bss段中的符号名重复,所以会报错-重复定义变量(multiple definition of `gb');

验证详情

0 NOTE

0.1 List files(验证时用到的文件)

验证时用到的文件(可在git获取)。

  1. # ls
  2. a_demo.out
  3. config.mk
  4. functions.c
  5. functions.o
  6. header.h
  7. main.c
  8. main.o
  9. Makefile
  10. README.md
  11. source_pre.i

0.2 Manual page - nm (part)

关于nm(用于列出目标文件的符号)工具的说明。

  1. NM(1)
  2. "C" The symbol is common. Common symbols are uninitialized data. When linking, multiple common symbols
  3. may appear with the same name. If the symbol is defined anywhere, the common symbols are treated as
  4. undefined references.
  5. "B"
  6. "b" The symbol is in the uninitialized data section (known as BSS).
  7. "D"
  8. "d" The symbol is in the initialized data section.

0.3 Macros

代码中用于方便演示而添加的两个宏。

  1. //header.h
  2. /*
  3. * __INIT_THE_VAR__ : Initialize variable"gb" in this header file.(CH:)
  4. * Define this macro(int gb = <x>;), GCC will report error:
  5. * (CH:开启这个宏,头文件中会定义并初始化变量gb,此时GCC会报错)
  6. * GCC Error - multiple definition of `gb'
  7. * (CH:重复定义变量gb)
  8. * __VAR_VAULE_ZERO__ : Initial vaule is 0.(CH:)
  9. * Define this macro(int gb = 0;), GCC will place the var to BSS section, else DATA section.
  10. * (CH:开启这个宏,头文件中会定义并初始化变量gb=0,GCC会把gb变量放到BSS段,初值不为0时放到DATA段)
  11. */

1. Compile(编译)

1.1 DEFINE(o), INIT( ), ZERO( )

Define (but not initialize) variable in header(CFLAGS += "-U__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__")

(CH:在头文件中定义但不初始化变量)

  1. make all-normal-create-obj CFLAGS+="-U__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__"
  2. CLEANING...
  3. rm -rvf ./*.out ./*.i ./*.o
  4. removed './source_pre.i'
  5. removed './functions.o'
  6. removed './main.o'
  7. rm -rvf /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/build
  8. gcc -c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c -o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.o -U__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__
  9. gcc -c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c -o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.o -U__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__
  10. BUILDING...
  11. gcc -E /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c >> source_pre.i
  12. FLAGS : -U__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__ ;
  13. SRCS:
  14. /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c
  15. gcc -o a_demo.out /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.o -U__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__

1.2 DEFINE(o), INIT(o), ZERO( )

Define & initialize variable in header(CFLAGS +=" -D__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__")

(CH:在头文件中定义并初始化变量为非零值)

  1. make all-normal-create-obj CFLAGS+="-D__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__"
  2. CLEANING...
  3. rm -rvf ./*.out ./*.i ./*.o
  4. removed './a_demo.out'
  5. removed './source_pre.i'
  6. removed './functions.o'
  7. removed './main.o'
  8. rm -rvf /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/build
  9. gcc -c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c -o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.o -D__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__
  10. gcc -c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c -o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.o -D__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__
  11. BUILDING...
  12. gcc -E /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c >> source_pre.i
  13. FLAGS : -D__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__ ;
  14. SRCS:
  15. /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c
  16. gcc -o a_demo.out /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.o -D__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__
  17. /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.o:(.data+0x0): multiple definition of `gb'
  18. /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.o:(.data+0x0): first defined here
  19. collect2: error: ld returned 1 exit status
  20. Makefile:167: recipe for target 'all-normal-create-obj' failed
  21. make: *** [all-normal-create-obj] Error 1

1.3 DEFINE(o), INIT(o), ZERO(o)

Define & initialize variable in header(CFLAGS +=" -D__INIT_THE_VAR__ -D__VAR_VAULE_ZERO__")

(在头文件中定义并初始化变量为零)

  1. # make all-normal-create-obj CFLAGS+="-D__INIT_THE_VAR__ -D__VAR_VAULE_ZERO__"
  2. CLEANING...
  3. rm -rvf ./*.out ./*.i ./*.o
  4. removed './source_pre.i'
  5. removed './functions.o'
  6. removed './main.o'
  7. rm -rvf /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/build
  8. gcc -c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c -o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.o -D__INIT_THE_VAR__ -D__VAR_VAULE_ZERO__
  9. gcc -c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c -o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.o -D__INIT_THE_VAR__ -D__VAR_VAULE_ZERO__
  10. BUILDING...
  11. gcc -E /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c >> source_pre.i
  12. FLAGS : -D__INIT_THE_VAR__ -D__VAR_VAULE_ZERO__ ;
  13. SRCS:
  14. /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.c /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.c
  15. gcc -o a_demo.out /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.o /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.o -D__INIT_THE_VAR__ -D__VAR_VAULE_ZERO__
  16. /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/functions.o:(.bss+0x0): multiple definition of `gb'
  17. /home/dramalife/note/70-gcc_gnu_compiler_collection/tips/Q_can_define_var_at_header/main.o:(.bss+0x0): first defined here
  18. collect2: error: ld returned 1 exit status
  19. Makefile:167: recipe for target 'all-normal-create-obj' failed
  20. make: *** [all-normal-create-obj] Error 1

2 Symbols

2.1 DEFINE(o), INIT( ), ZERO( )

List symbol - define (but not initialize) variable in header(CFLAGS +=" -U__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__")

  1. # nm main.o
  2. 000000000000000a r __func__.2252
  3. U functionb
  4. 0000000000000004 C gb
  5. U _GLOBAL_OFFSET_TABLE_
  6. 0000000000000000 T main
  7. U printf
  8. # nm function.o
  9. 0000000000000010 r __func__.2252
  10. 0000000000000000 T functionb
  11. 0000000000000004 C gb
  12. U _GLOBAL_OFFSET_TABLE_
  13. U printf

2.2 DEFINE(o), INIT(o), ZERO( )

List symbol - define & initialize variable in header(CFLAGS +=" -D__INIT_THE_VAR__ -U__VAR_VAULE_ZERO__")

  1. # nm main.o
  2. 000000000000000a r __func__.2252
  3. U functionb
  4. 0000000000000000 D gb
  5. U _GLOBAL_OFFSET_TABLE_
  6. 0000000000000000 T main
  7. U printf
  8. # nm function.o
  9. 0000000000000010 r __func__.2252
  10. 0000000000000000 T functionb
  11. 0000000000000000 D gb
  12. U _GLOBAL_OFFSET_TABLE_
  13. U printf

2.3 DEFINE(o), INIT(o), ZERO(o)

List symbol - define & initialize variable in header(CFLAGS +=" -D__INIT_THE_VAR__ -D__VAR_VAULE_ZERO__")

  1. # nm main.o
  2. 000000000000000a r __func__.2252
  3. U functionb
  4. 0000000000000000 B gb
  5. U _GLOBAL_OFFSET_TABLE_
  6. 0000000000000000 T main
  7. U printf
  8. # nm function.o
  9. 0000000000000010 r __func__.2252
  10. 0000000000000000 T functionb
  11. 0000000000000000 B gb
  12. U _GLOBAL_OFFSET_TABLE_
  13. U printf

Summary(总结)

Define and/or init variable in header files referenced by multiple source files.

(CH:在 被多个源文件引用的 头文件 中 定义和初始化变量。)

变量定义时,如果不赋初值,GCC会把它放到COMMON段,COMMON类型的符号是未初始化的数据。链接时,gcc允许多个COMMON符号以相同的名称出现(在多个地方被定义)。

变量定义时,如果赋了初值,GCC会把它放到DATA或者BSS段,链接时,这两种类型的符号不允许重名。

INIT ZERO Compile Section of var
- - PASS COMMON
v - ERR DATA
v v ERR BSS

[Linux][C][gcc][tips] 在头文件中定义变量引发的讨论的更多相关文章

  1. 不要在.h文件中定义变量

    今天在头文件.h中初始化了一个数组和函数,在编译的时候提示这个数组和函数重新定义了,检查后发现,犯了一个致命的错误,在头文件中定义变量... 以下引用别人的一篇说明,警示自己. C语言作为一种结构化的 ...

  2. c语言头文件中定义全局变量的问题

    c语言头文件中定义全局变量的问题 (转http://www.cnblogs.com/Sorean/) 先说一下,全局变量只能定义在 函数里面,任意函数,其他函数在使用的时候用extern声明.千万不要 ...

  3. C语言头文件中定义全局变量导致重复定义错误

    合作方升级SDK后,程序编译出现变量重复定义的错误,通过错误提示无法找到什么位置重复定义了,但确定是引入新SDK后才出现的错误,从SDK的头文件中查找,最终发现在头文件中定义了全局变量 我们的项目在多 ...

  4. C语言之在头文件中定义全局变量

    通常情况下,都是在C文件中定义全局变量,在头文件中声明,但是,如果我们定义的全局变量需要被很多的C文件使用的话,那么将全局变量定义在头文件里面会方便很多,那到底是如何实现的? os_var.c文件内容 ...

  5. C++ vector 实现二维数组时, 在类的头文件中定义时遇到"应输入类型符"的问题?

    见下,当我在类的声明文件中定义二维vector时,提示我应输入类型说明符; 但是相同的格式定义,在类中将二维vector修改为在源文件中定义就可以顺利通过,并顺利执行打印 打印结果如下: 望大神来解惑 ...

  6. 在C的头文件中定义的结构体,如何在cpp文件中引用

    解决方案1:在cpp文件中放置.c,且在该文件中引用变量 解决方案2:在一个cpp文件中包含.c,但在另一个cpp文件中使用结构体变量 cpp文件1 cpp文件2 #include "dia ...

  7. 关于在.H文件中定义变量

    KEIL中,在".H"文件定义变量. 如果该".H"文件同时被两个".C"文件调用,则会出现重复定义错误(*** ERROR L104: M ...

  8. linux下gcc默认搜索头文件及库文件的路径

    一.头文件gcc 在编译时如何去寻找所需要的头文件:※所以header file的搜寻会从-I开始※然后找gcc的环境变量 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC ...

  9. 编写linux驱动所用到的头文件(转)

    转自:http://blog.csdn.net/lufeiop02/article/details/6448497 关于linux驱动(应用)程序头文件使用 收藏 驱动程序: #include < ...

随机推荐

  1. Docker企业级镜像仓库harbor(vmware 中国团队)

    第一步:安装docker和docker-compose 第二步:下载harbor-offline-installer-v1.3.0.tgz 第三步:上传到/opt,并解压 第四步:修改harbor.c ...

  2. python运算符和常用数据类型转换

    运算符 算术运算符 运算符 描述 实例 + 加 两个对象相加 a + b 输出结果 30 - 减 得到负数或是一个数减去另一个数 a - b 输出结果 -10 * 乘 两个数相乘或是返回一个被重复若干 ...

  3. java 7 try with resources理解

    参考文档: 官方文档:http://docs.oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html#su ...

  4. json/xml processing model与xml和json的简要区别

    1.JavaScript Object Notation(JSON) JSON是一种轻量级数据交换格式,广泛用作通用格式,用于序列化和反序列化通过Internet相互通信的应用程序中的数据.这些应用程 ...

  5. DocumentFragment的相关用法

    额,今天看了vue1.0关于模板渲染的知识,认识了DocumentFragment这个东西,它相当于一个节点容器,我们对他使用appendChild时,只有它的子节点会被插入进去,它本身不会插入进去, ...

  6. Python---12函数式编程------12.1高阶函数

    函数式编程 函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计 ...

  7. 台式机安装CentOS7.6 Minimal ISO系统并增加图形化桌面

    需求:公司测试环境因业务原因,需要在台式电脑上安装带桌面的CentOS系统,因同事有一个7.6版本Minimal ISO镜像的安装U盘,为了图方便没有去下载everything ISO镜像,而是待同事 ...

  8. Selenium的Web自动化测试(送源码)

    8.1  Selenium自动化测试准备 1.Selenium介绍 Selenium是一个Web开源自动化测试框架,页面级操作,模拟用户真实操作,API从系统层面触发事件. Selenium 1.0  ...

  9. legend图例

    import matplotlib.pyplot as plt import numpy as np x=np.linspace(-3,3,50) y1=x*2+1 y2=x**2 plt.plot( ...

  10. MyBatis连接MySQL8配置

    <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</a ...