免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 35253 | 回复: 6

关于“initializer element is not constant ”的编译错误 [复制链接]

论坛徽章:
0
发表于 2008-10-11 18:29 |显示全部楼层
试验用的gcc版本比较老。

以下两段代码,如果命名为 *.c 文件,在GCC下编译,都会报错,错误信息是“initializer   element   is   not   constant ”。

但是如果把 *.c 文件改名为 *.cc文件,用g++编译,就不会报错。

谁能详细解释一下这是为什么。

// code 1
int i = 10;
int j = i + 4;


// code 2
int i = 10;
int main()
{
    static int j = i;
    retrun 0;
}

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
发表于 2008-10-11 20:06 |显示全部楼层

回复 #1 kiffa 的帖子

语言的规定不一样呗

论坛徽章:
3
戌狗
日期:2014-09-10 17:07:162015年辞旧岁徽章
日期:2015-03-03 16:54:15wusuopu
日期:2016-06-17 17:43:45
发表于 2008-10-12 18:36 |显示全部楼层

论坛徽章:
0
发表于 2008-10-12 21:12 |显示全部楼层
谢楼上的,这下弄清楚了。

在C++中对于以下语句:
// 全局域
int i = 3;
int j = i;

编译时将i 放入.data 段,设置其值为3.

而对于j ,编译器遇到这种语句,只知道j = i ,由于 i 是变量,不是常量,编译器无法在编译时直接得到它的值,编译器只会找到i 的地址, 然后读取这个地址的内容,再把这个内容写入 j 的地址。

编译器不能够直接用3 来初始化 j ,因为计算机不是人,不懂简单的人类逻辑,我们想“因为 i = 3,而 j = i,所以j = 3",而计算机无法在逻辑上由i = 3 和 j = i 来推出j = 3,就好像图灵机不可能证明某个论题的真伪一样。

计算机只会“取 i 的地址,把3 放到 i 的地址中,取 i 的地址,读取这个地址中的内容,取 j 的地址,把这个内容 写入j 的地址。” 它不会思考,不懂因果,只是机械地执行指令。编译器无法在编译时求得一个非常量的值,它只能在运行时通过读取变量地址来间接得到变量的值,而全局变量在编译时就必须确定其值,故C有静态存储区数据必须用常量初始化的规定。

在编译时只能用常量去初始化一个静态存储区的数据,而不能用“读取某个变量的内容”来初始化,所以编译器会将j 放入 .bss段,默认值为0 ,然后添加一条语句在运行时读取i 的值,再赋给j。这条语句在调用main()之前完成。

论坛徽章:
0
发表于 2008-10-12 21:23 |显示全部楼层
一个对比:

对于语句:
int i = 3

int main()
{
    int j = i;
    ...
}

在编译时不需要确定局部变量 j 的值,而是在运行时读取i 的值来赋给 j. 编译连接后的可执行文件中不会存放j 的值,只有相应的赋值语句的代码。与此相对的,由于i 是全局变量,存储在静态存储区,因此在编译时其值就需要确定其值,在目标文件中会分配空间来存放 i 的值,运行时不会有赋值语句来给 i 赋值, 没有对应的代码。

而对于语句:
int i = 3;
int j = i;

由于j 是全局变量,存储在静态存储区,因此也需要在编译时确定其值。而i 是变量,不是常量,i 的值无法在编译时确定,这就造成j 的值也无法在编译时确定,所以C对此就会报错。而C++采取了另外一种做法,在编译时简单的把 j 作为未初始化的全局变量放入.bss 区,其默认值为0,然后添加一条语句在运行时给 j 赋值,并保证这条语句在 main函数开始之前执行。因此j 的初始化实际上实在运行时完成的。

[ 本帖最后由 kiffa 于 2008-10-12 21:25 编辑 ]

论坛徽章:
0
发表于 2008-10-13 09:10 |显示全部楼层
新版本的gcc能不能编译通过呢?我觉得可以,因为我经常就是同时声明和定义的,虽然不是全局或者static

论坛徽章:
0
发表于 2014-05-22 10:28 |显示全部楼层
学习了。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

PostgreSQL中国大会,早鸟票抢购!

PostgreSQL中国大会,早鸟票抢购!
2019年11月29~11月30日,由 PostgreSQL中文社区与ITPUB联合主办的第九届《PostgreSQL 中国技术大会》将在北京隆重召开。PostgreSQL 作为功能最强的的开源关系型数据库之一,得到了越来越多企业的推广和运用,也越来越受到广大技术爱好者的欢迎和重视。这将是 PostgreSQL 的又一次交流盛会。




----------------------------------------

点击报名>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP