【C语言】有关gcc优化和全局变量的疑惑

js_xj 2013-10-12 03:39:29
现有文件main.c fun.c fun.h,编译环境ubuntu10.10,gcc-4.4.3。
main.c

#include <stdio.h>
#include "fun.h"

int a;
int main(void)
{
fun();

printf("[main] &a = %p\n", &a);
printf("[main] a = 0x%X\n", a);
}


fun.c

#include <stdio.h>
#include "fun.h"

int a;
void fun(void)
{
a = 0xff;

printf("[fun] &a = %p\n", &a);
printf("[fun] a = 0x%X\n", a);
}


fun.h

#ifndef _FUN__H
#define _FUN__H

void fun(void);

#endif


编译:gcc -o main main.c fun.c(无警告无错)
执行:./main
结果:
[fun] &a = 0x804a01c
[fun] a = 0xFF
[main] &a = 0x804a01c
[main] a = 0xFF

请问:定义了两个全局变量a,为什么在连接的过程中,连接器没有报重复定义的错呢?
ps:我是看了《C陷阱与缺陷》书 “【第4章 连接】 4.2声明与定义”做的实验。
...全文
424 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
AnYidan 2013-10-12
  • 打赏
  • 举报
回复
一般选离自己最近的变量
一根烂笔头 2013-10-12
  • 打赏
  • 举报
回复
这个应该和GCC参数有关!就像你说的那样,优化了!全局变量都是放在data段中,是容的不得重复的!
js_xj 2013-10-12
  • 打赏
  • 举报
回复
也就是说:两个int a;都是声明,那声明与定义的具体区别呢?网上有说 “声明一个变量意味着向编译器描述变量的类型,但并不为变量分配存储空间。 定义一个变量意味着在声明变量的同时还要为变量分配存储空间。” 这句话我怎么认为不对呢

#include <stdio.h>
#include "fun.h"
 
int a;
int main(void)
{
    printf("[main] &a = %p\n", &a);

    fun();
 
    printf("[main] &a = %p\n", &a);
    printf("[main] a = 0x%X\n", a);
}
结果: [main] &a = 0x804a01c [fun1] &a = 0x804a01c [fun1] a = 0xFF [main] &a = 0x804a01c [main] a = 0xFF 第一条printf的&a是有地址的啊?
图灵狗 2013-10-12
  • 打赏
  • 举报
回复
要加上 -Wredundant-decls选项才会警告,默认是关闭的:

gcc -Wredundant-decls -o main main.c fun.c
引用 楼主 js_xj 的回复:
现有文件main.c fun.c fun.h,编译环境ubuntu10.10,gcc-4.4.3。 main.c

#include <stdio.h>
#include "fun.h"

int a;
int main(void)
{
	fun();

	printf("[main] &a = %p\n", &a);
	printf("[main] a = 0x%X\n", a);
}
fun.c

#include <stdio.h>
#include "fun.h"

int a;
void fun(void)
{
	a = 0xff;

	printf("[fun] &a = %p\n", &a);
	printf("[fun] a = 0x%X\n", a);
}
fun.h

#ifndef _FUN__H
#define _FUN__H

void fun(void);

#endif
编译:gcc -o main main.c fun.c(无警告无错) 执行:./main 结果: [fun] &a = 0x804a01c [fun] a = 0xFF [main] &a = 0x804a01c [main] a = 0xFF 请问:定义了两个全局变量a,为什么在连接的过程中,连接器没有报重复定义的错呢? ps:我是看了《C陷阱与缺陷》书 “【第4章 连接】 4.2声明与定义”做的实验。
做或不做 2013-10-12
  • 打赏
  • 举报
回复
#include <stdio.h> #include <stdlib.h> int a= 2; int a; int main() { printf("%d\n",a); printf("Hello world!\n"); return 0; } 可以通过编译 #include <stdio.h> #include <stdlib.h> int a; int a = 2; int main() { printf("%d\n",a); printf("Hello world!\n"); return 0; } 也可以通过编译 #include <stdio.h> #include <stdlib.h> int a = 5 ; int a = 4; int main() { printf("%d\n",a); printf("Hello world!\n"); return 0; } 错误不可以通过编译 说明int a; 在作为全局变量的时候 只有在用与赋值的时候 才是真正意义上的定义 所以不会报重复定义
做或不做 2013-10-12
  • 打赏
  • 举报
回复
因为这是俩个int a是声明 #include <stdio.h> #include <stdlib.h> int a; int a; int main() { printf("Hello world!\n"); return 0; } 可以通过编译 不报错 是因为编译器给优化掉了吧
第1篇 Linux下C语言基础 第1章 Linux简介 1.1 GNU简介 1.2 Linux简介 1.2.1 Linux发展史 1.2.2 Linux发行版 1.2.3 Linux内核版本 1.2.4 Linux与UNIX的关系 1.2.5 Linux在服务器方面的发展 1.2.6 Linux在嵌入式系统方面的发展 1.2.7 Linux在桌面系统方面的发展 1.3 Linux环境下的其他编程语言 1.3.1 C++ 1.3.2 Java 1.3.3 Perl 1.3.4 Python 1.3.5 Ruby 1.3.6 PHP 第2章 控制结构 2.1 goto语句 2.1.1 C语言中的无条件跳转 2.1.2 使用goto语句进行出错处理 2.1.3 出错处理的一般模型 2.2 C语言中的分支结构 2.2.1 分支结构的翻译 2.2.2 使用goto语句实现分支结构 2.3 短路计算 2.3.1 短路计算 2.3.2 &&运算的短路计算 2.3.3 ||运算的短路计算 2.4 C语言中的循环结构 2.4.1 while循环 2.4.2 do…while循环 2.4.3 for循环 2.5 switch语句 2.5.1 switch语句的应用 2.5.2 使用goto语句实现switch语句 2.6 优化控制结构 2.6.1 表达式优化——使用替换程序中的乘除法 2.6.2  表达式优化——常量折叠 2.6.3 表达式优化——使用数学公式 2.6.4 表达式优化——存储问题 2.6.5 分支优化——改变判断顺序 2.6.6 分支优化——使用switch语句 2.6.7 循环优化——一次性计算 第3章 C语言中的函数 3.1 函数的本质 3.2 变量的作用域和生命期 3.2.1 全局变量 3.2.2 局部变量 3.3 变量的初始值 3.3.1 全局变量的初始值 3.3.2 局部变量的初始值 3.4 与函数有关的优化 3.4.1 函数调用与程序优化 3.4.2 变量存储优化 3.5 编写多文件程序——变量的存储类别 3.5.1 存储类别 3.5.2 static变量的作用——改变变量的生命期 3.5.3 static变量的作用——实现封装和模块化设计 3.6 编写多文件的程序——链接的作用 3.6.1 链接多个文件 3.6.2 链接时符号解析规则 3.6.3 链接规则的应用 3.7 可变参数 3.7.1 可变参数的概念 3.7.2 实现一个简单的可变参数的函数 3.7.3 可变参数实例 3.7.4 关于printf函数的疑问——缺少整型参数 3.7.5 关于printf函数的疑问——缺少字符串地址参数 第4章 C语言中的指针与字符串 4.1 sizeof运算符 4.1.1 sizeof运算符的应用——得到内置类型的大小 4.1.2 sizeof运算符的应用——得到复合类型的大小 4.2 指针的应用 4.2.1 指针与别名陷阱 4.2.2 数组的指针 4.2.3 指针的指针 4.2.4 指针与参数传递 4.2.5 指针类型的意义 4.2.6 void*型指针 4.3 函数的指针 4.3.1 C语言中的函数指针 4.3.2 函数指针的应用——回调函数 4.3.3 函数指针数组 4.4 字符串 4.4.1 字符串与字符数组 4.4.2 字符串与指针 4.4.3 限定修饰符const 4.4.4 const关键字修饰指针——在指针定义之前 4.4.5 const关键字修饰指针——在指针定义之中 4.4.6 const关键字修饰指针——在指针定义之前和定义之中 4.4.7 使用const关键字的意义 第5章 C语言的高级技术 第2篇 C语言开发环境 第6章 vi与vim编辑器 第7章 gcc编译器 第8章 makefile 第9章 gdb 第3篇 Linux进程操作 第10章 进程环境 第11章 进程控制 第12章 时间和日历历程 第13章 信号及信号处理 第14章 进程间通信 第15章 线程 第4篇 Linux文件操作 第17章 文件I/O 第18章 文件管理 第19章 目录操作 第20章 特殊文件 第21章 基于流的I/O 第5篇 Linux网络编程 第22章 TCP和UDP协议 第23章 网络编程基础 第24章 网络编程进阶 第25章 网络编程实例——实现文件传输程序 第26章 网络编程实例——简单的Web服务器 第6篇 shell脚本知识 第27章 shell脚本基础 第28章 shell脚本中的控制结构 844

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧