原帖由 zx_wing 于 2009-5-17 00:26 发表
我想举一个自己最近在项目中犯的错误来说明要踏踏实实做人,不要做装B青年
在代码中,我需要在一个library和一个daemon之间通过socket传送数据包,包的格式定义如下(为了简化,我就用最简单的数据类型举例 ...
原帖由 yhb04 于 2009-5-17 18:08 发表
这算鸟奇技淫巧。
LZ既然用到GCC的零长数组,就应该仔细阅读结构布局的说明。显然LZ没仔细搞清楚GCC的C扩展就乱用。
要是嫌阅读说明麻烦,把最后的data[0]改成data[1]不什么事都没了嘛。
原帖由 yhb04 于 2009-5-17 19:11 发表
...
#define offsetof(type, element) ((unsigned long)&((type *)0)->element)
cmd->size = offsetof(packet, data) + 20;//cmd->size的计算不要用sizeof(packet)
...
原帖由 yhb04 于 2009-5-17 19:11 发表
typedef struct {
int head;
int size; //指明整个包的长度
char reply;
char data[1];
} packet;
packet* cmd = malloc (sizeof(packet) + 20); //多空几个字节无所谓
...
Each member is assigned to the lowest available offset with the appropriate
alignment. This may require internal padding, depending on the previous
member.
A structure¡¯s size is increased, if necessary, to make it a multiple of the
alignment. This may require tail padding, depending on the last member.
原帖由 baicj 于 2009-5-17 19:58 发表
如同你所说, 问题在于daemon端用sizeof计算的struct head大小, 而library端用offsetof计算struct head大小, 两者结果不一致. 修改位data[1]不会有帮助, 解决问题的办法也正如你的代码, 统一用offsetof来代替s ...
原帖由 zx_wing 于 2009-5-17 22:29 发表
呵呵,小伙子水平不高口气不小。
首先char data[1]解决不了问题,char data[0]不是C标准,前者是C标准而已。
其次,gcc手册没有对零长数组有太多解释,这本来就是个简单的东西。其次这里的内存布局和是不是 ...
原帖由 yhb04 于 2009-5-17 23:33 发表
猜不猜不是你说了算,现在写一个C编译器也不是天方夜谈,你对结构体的布局不了解并不表示别人也这样。装B不是靠发帖数多。您爱装就继续装吧。
对了,GCC的零长数组满足不了您的需求,倒是C99 里的东西可以符 ...
原帖由 zx_wing 于 2009-5-17 23:42 发表
哈哈,小伙子,装B也不是靠说话拽就可以了。要像我这样,拿出大量的证据证明装的正确。
还有一点大忌就是,装之前要还是要真懂一点再装,不然像你这样稍微装一下就露马脚就丢人了。
原帖由 zx_wing 于 2009-5-17 23:42 发表
哈哈,小伙子,装B也不是靠说话拽就可以了。要像我这样,拿出大量的证据证明装的正确。
还有一点大忌就是,装之前要还是要真懂一点再装,不然像你这样稍微装一下就露马脚就丢人了。
>>你对结构体的布局不 ...
原帖由 yhb04 于 2009-5-17 23:55 发表
要讲内存布局也不用扯这么多平台。
从你的第一贴就可以看出你连自己的开发平台的对齐就不清楚,扯这么多平台显得你很厉害是吧、可喜第一贴就把你自己的马脚给露了。
原帖由 zx_wing 于 2009-5-18 00:02 发表
你小子还真来劲了呢。本来都不想和你扯,你还起劲。
你起劲就算了,还净乱讲,新到CU的朋友看你这么牛B轰轰的嚷嚷我不说话,还以为你讲的是对的哦。最烦你这种不懂又要在这里误导人的。
>>要讲内存布局也 ...
原帖由 zx_wing 于 2009-5-18 00:07 发表
>>LZ既然用到GCC的零长数组,就应该仔细阅读结构布局的说明。显然LZ没仔细搞清楚GCC的C扩展就乱用。
把你说的说明给我找出来,贴到这里。我倒是孤陋寡闻不清楚编译手册什么时候会规定架构ABI管的东西
>>要 ...
原帖由 yhb04 于 2009-5-18 00:17 发表
>>要是嫌阅读说明麻烦,把最后的data[0]改成data[1]不什么事都没了嘛。
给我讲讲data[1]有什么用。把内存布局画出来,证明这样改有用。
你要我说什么呢,按照你上面定义的结构,以X86的某个典型编译器为例, ...
原帖由 zx_wing 于 2009-5-18 09:07 发表
呵呵,data[0]也和前面的紧邻的
如果仅仅是malloc(sizeof(packet)),则data[1]情况变为:
head (4 bytes) size (4 bytes) reply (1 byte) data[1] (1 bytes) padding (2 bytes)
如果是data[0]:
head (4 ...
原帖由 yhb04 于 2009-5-18 09:55 发表
谁说内存内存布局不一样了,只是改成data[1]啥的就可以正确求的offset(data,packet)的值了。
gcc的data[0]的实现就比较诡异了,实际应用中用这个东西是为了应付变长结构,这个时候使用sizeof(packet)是不适宜 ...
原帖由 yhb04 于 2009-5-18 09:59 发表
还有,这个问题本身跟各个平台的ABI没有太大关系。
我只假设你在X86平台上用gcc编译2个程序,互相通信。
如果你说你的一个程序是X86的gcc编译的程序,另一个是其他平台其他编译器编译的程序。那当我前面什么都 ...
原帖由 zx_wing 于 2009-5-18 10:03 发表
》》只是改成data[1]啥的就可以正确求的offset(data,packet)的值了、
data[0],data[1]通过offsetof求值是一样的,因为它们之前的内存布局相同
原帖由 yhb04 于 2009-5-18 10:06 发表
据我所知,结构体内的域之间的padding不是ABI规定的,而是编译器的具体实现。
C89:
Each non-bit-field member of a structure or union object is aligned
in an implementation-defined manner appro ...
原帖由 zx_wing 于 2009-5-18 10:10 发表
嗯,现在像讲技术的态度了。
implementation-defined manner,确实是编译具体实现,但编译器的具体实现遵照的就是架构ABI。不论是编译器还是操作系统,都是必须遵照它。
implementation-defined manner 指就 ...
原帖由 yhb04 于 2009-5-18 10:05 发表
typedef struct {
int head;
int size; //指明整个包的长度
char reply;
char data[1];
} packet;
packet* cmd = malloc (sizeof(packet) + 20); //多空几个字节无所谓 ...
如同你所说, 问题在于daemon端用sizeof计算的struct head大小, 而library端用offsetof计算struct head大小, 两者结果不一致. 修改位data[1]不会有帮助, 解决问题的办法也正如你的代码, 统一用offsetof来代替sizeof, 或者用sizeof来代替offsetof.
原帖由 zx_wing 于 2009-5-18 10:10 发表
嗯,现在像讲技术的态度了。
implementation-defined manner,确实是编译具体实现,但编译器的具体实现遵照的就是架构ABI。不论是编译器还是操作系统,都是必须遵照它。
implementation-defined manner 指就 ...
原帖由 yhb04 于 2009-5-18 10:13 发表
ABI主要控制的是操作系统与应用程序的系统调用的惯例,虽然在系统调用中如果传结构体参数,那么结构体必须遵照OS的ABI来控制padding,但是这并不是强制的。
原帖由 zx_wing 于 2009-5-17 00:26 发表
我想举一个自己最近在项目中犯的错误来说明要踏踏实实做人,不要做装B青年
在代码中,我需要在一个library和一个daemon之间通过socket传送数据包,包的格式定义如下(为了简化,我就用最简单的数据类型举例 ...
原帖由 zx_wing 于 2009-5-17 00:26 发表
我想举一个自己最近在项目中犯的错误来说明要踏踏实实做人,不要做装B青年
在代码中,我需要在一个library和一个daemon之间通过socket传送数据包,包的格式定义如下(为了简化,我就用最简单的数据类型举例 ...
原帖由 ShadowStar 于 2009-5-18 12:32 发表
其实,我觉得,LZ把typedef struct {
int head;
int size; //指明整个包的长度
char reply;
char data[0];
} packet;
改为typedef struct {
struct {
i ...
是找到了问题:
sizeof (packet) == 12;
这是合理的,char reply被padding成了4个字节,而char data[0]字节为0。
但,offsetof(packet, data) == 9,在计算偏移时,char reply为一个字节,没有padding。
所以packet_data_len每次都会返回比真实的数据多3个字节 ……
原帖由 思一克 于 2009-5-18 13:42 发表
----------------------------
LZ分析的不对。
offsetof(packet, data)=9 说明没有将reply padding为4个字节。
呵呵,data[0]也和前面的紧邻的
如果仅仅是malloc(sizeof(packet)),则data[1]情况变为:
head (4 bytes) size (4 bytes) reply (1 byte) data[1] (1 bytes) padding (2 bytes)
如果是data[0]:
head (4 bytes) size (4 bytes) reply (1 byte) data[0] (0 bytes) padding (3 bytes)
不管data[0],data[1],malloc(sizeof(packet) + 20)后,之后都没有padding。所以两者内存布局本质是一样的,把data[0]改成data[1]没有任何帮助。
原帖由 ShadowStar 于 2009-5-18 12:32 发表
其实,我觉得,LZ把typedef struct {
int head;
int size; //指明整个包的长度
char reply;
char data[0];
} packet;
改为typedef struct {
struct {
i ...
原帖由 zx_wing 于 2009-5-17 00:26 发表
我想举一个自己最近在项目中犯的错误来说明要踏踏实实做人,不要做装B青年
在代码中,我需要在一个library和一个daemon之间通过socket传送数据包,包的格式定义如下(为了简化,我就用最简单的数据类型举例 ...
原帖由 landylau_ren 于 2009-5-19 13:59 发表
![]()
很naive的一个错误啊 有必要花我这么长时间去看一堆乱七八糟的讨论
少点争论,有事说事
我还以为有什么高深的技术含量咧
真是个装13问题
原帖由 OwnWaterloo 于 2009-5-19 16:23 发表
使用#pragma pack或者 __attribute__((packed))是解决了padding问题。
但是会不会导致新的,未对齐数据访问的问题?
原帖由 雨过白鹭洲 于 2009-5-27 00:29 发表
不同机器间的数据交换,除了对齐,还有大端小端等等问题
你定义struct来传报文,当然会出问题了;传二进制数据也同样是不可靠的
感谢楼主分享经验。。
欢迎光临 Chinaunix (http://bbs.chinaunix.net/) | Powered by Discuz! X3.2 |