免费注册 查看新帖 |

Chinaunix

广告
  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: wwdwwd
打印 上一主题 下一主题

[C] 为什么可以定义两个相同的结构体而不出错? [复制链接]

论坛徽章:
0
11 [报告]
发表于 2009-11-22 03:24 |只看该作者
只在有二义性的时候,才有必要报错,gcc 没有必要负责工程上的事情。
你带 -v 参数编译下,看一下编译过程。
gcc 先将test 编译成汇编,然后二进制,将test2编译成汇编,然后编译成2进制。
连接器连接的是.o文件,可以认为连接的是可执行文件,对于这样的文件,变量已经没有意义,
只是一堆内存,但是过程仍然有意义。所以你可以重复定义变量,但不能重复定义过程。如果你在
test.c中也定义一个test2(),就会出错。

变量标示的只是一块内存,没有任何类型的区别,只有大小区别,在汇编级别,只有过程,才有意义。

从大的角度来说,c语言并不是一门语言,只是汇编的一个前端。老祖宗都那么抽象了,子孙有必要那么实在么?

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
12 [报告]
发表于 2009-11-22 11:44 |只看该作者
原帖由 peidright 于 2009-11-22 03:24 发表
只在有二义性的时候,才有必要报错,gcc 没有必要负责工程上的事情。
你带 -v 参数编译下,看一下编译过程。
gcc 先将test 编译成汇编,然后二进制,将test2编译成汇编,然后编译成2进制。
连接器连接的是.o ...

我做点补充

事实上,Test1.c和Test2.c的变量信息还是被保留的(通过符号表)

此外,函数(您所说的过程)和变量是同等被对待的。所以,您所谓的过程和变量的区别是不存在的。
我在上贴所说的变量是指局部变量。

全局变量和全局函数同样会引起Link冲突。但你可以在全局变量前加”Static“表示它只在本文件中有效以避免名字冲突。

论坛徽章:
0
13 [报告]
发表于 2009-11-22 13:12 |只看该作者

无语

不少回复没有说到点子上,这关类型什么事?
ls已经有人给出答案,lz请自己思考一下

关于namespace,请考虑如下代码
int i;

int main()
{
    int i;
}

int main()
{
    int i;
    int i;
}

两段代码会不会出错?哪个会出错?(很显然)
typedef也是一样的,你可以把int i替换成typedef int MY_INT,是否重复定义的判定是一样的

至于你举的例子中,两个文件是分开的,就有各自的namespace
否则的话,一个.c文件中使用了i这个名字(作为全局变量),另一个就不能用了?
如果把两个typedef写到一个文件中(并且在同一个作用域),自然就是冲突了
如果写成这样,也不会出错
typedef int MY_INT;
int main()
{
    typedef int MY_INT;
}

论坛徽章:
0
14 [报告]
发表于 2009-11-22 13:28 |只看该作者
两个类型定义如果满足“One-Definition Rule, ODR”,那么它们被认为是同一定义。

ODR:
(1)位于不同编译单元
(2)定义完全相同(token-for-token identical)
(3)两个定义中的token的意义相同

论坛徽章:
0
15 [报告]
发表于 2009-11-22 13:34 |只看该作者
如果目标代码里面没有结构体的信息,那岂不是也没有类的信息?

那这样怎么能够抛出一个异常类由catch捕获?

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
16 [报告]
发表于 2009-11-22 15:46 |只看该作者
原帖由 皇家救星 于 2009-11-22 13:34 发表
如果目标代码里面没有结构体的信息,那岂不是也没有类的信息?

那这样怎么能够抛出一个异常类由catch捕获?


这个是由代码实现的。。。实现和编译器有关。一种常用的实现是在Stack中Construct一个异常处理帧,出现异常时代码将Jmp到异常处理代码,而正常处理时,程序将走正常流程


此外,和Namespace无关。Namespace是和变量相关的术语(事实上我从来不使用这个术语),和结构体(类型)没有任何关系。
说Namespace和Struct有关,正如说在二个Namespace中,Int这个关健字代表不同的意义一样(在不被重定义的情况下),而事实上,Namespace只有对于Int I;后面的I的关系,它用来约束I(变量)而不是Int(类型)。

论坛徽章:
0
17 [报告]
发表于 2009-11-26 10:56 |只看该作者
原帖由 lemoncookie 于 2009-11-22 13:12 发表
不少回复没有说到点子上,这关类型什么事?
ls已经有人给出答案,lz请自己思考一下

关于namespace,请考虑如下代码
int i;

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



两个文件中用同一个名称i作为全局变量确实是不可以的,如果两个都是强符号的话,例如他们都已经初始化了,这我是可以理解的。因为在链接的时候要做重定位,每个其他的文件对全局变量的引用都会被重定位为全局变量的真实地址,如果有不同的两个全局变量的地址的话,那链接器就不知道改重定位到哪个地址了,所以要报错。但两个同名结构体就可以定义在两个文件中我还是不理解,请指教。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
18 [报告]
发表于 2009-11-26 11:01 |只看该作者
我觉得这个问题主要还是由于 gcc 版本不够高所导致,
如果 gcc 8.0 出来了,也许 -Wall 会有个警告。

论坛徽章:
0
19 [报告]
发表于 2009-11-26 11:02 |只看该作者
原帖由 folklore 于 2009-11-22 02:52 发表
因为Test1.c和Test2.c是分开编译的,编译Test1.C的时候编译器看不到Test2.c
同样的Test2.c编译时也看不到Test1.c

Gcc -c test1.c -o test1.o  #目标代码Test1.o,不会有Struct的信息.就算是int i;目标代码也不 ...

如果目标代码中没有结构体信息的话,那怎么知道某个变量是结构体或其它类型的变量?如何采用成员符号进行引用?
比如我malloc一个结构体,然后引用其中的成员变量,程序怎么会知道呢?
我知道代码段肯定是有这些信息的,数据段我不知道是怎么存储的

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
20 [报告]
发表于 2009-11-26 11:03 |只看该作者
原帖由 wwdwwd 于 2009-11-26 11:02 发表

如果目标代码中没有结构体信息的话,那怎么知道某个变量是结构体或其它类型的变量?如何采用成员符号进行引用?
比如我malloc一个结构体,然后引用其中的成员变量,程序怎么会知道呢?
我知道代码段肯定是有 ...

所以才需要 include 啊。
笨笨
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP