can';我不理解这个联盟
我在ideone.com上尝试了这段代码,它符合要求,但我无法解释发生了什么,任何帮助都会很好:) 代码如下:can';我不理解这个联盟,c,layout,unions,C,Layout,Unions,我在ideone.com上尝试了这段代码,它符合要求,但我无法解释发生了什么,任何帮助都会很好:) 代码如下: #include <stdio.h> typedef union { unsigned char* g_pointer; struct { unsigned short local_addr; unsigned char globle_page; } g_l;
#include <stdio.h>
typedef union {
unsigned char* g_pointer;
struct {
unsigned short local_addr;
unsigned char globle_page;
} g_l;
} Gld_WordType;
int main()
{
int Idx;
Gld_WordType test;
test.g_l.globle_page = 0x13;
test.g_l.local_addr = 0xfff0;
printf("g_pointer: %x\n
local_addr: %x\n
globle_page: %x\n",
test.g_pointer,
test.g_l.local_addr,
test.g_l.globle_page);
test.g_pointer++;
printf("g_pointer: %x\n
local_addr: %x\n
globle_page: %x\n",
test.g_pointer,
test.g_l.local_addr,
test.g_l.globle_page);
return 0;
}
如果我简单地切换local\u addr
和globle\u page
的顺序,结果会有所不同:
typedef union {
unsigned char* g_pointer;
struct {
unsigned char globle_page; // Changed order here.
unsigned short local_addr; // And here
} g_l;
} Gld_WordType;
这一次,结果是:
g_pointer: 13fff0
local_addr: fff0
globle_page: 13
g_pointer: 13fff1
local_addr: fff1
globle_page: 13
g_pointer: fff00013
local_addr: fff0
globle_page: 13
g_pointer: fff00014
local_addr: fff0
globle_page: 14
好的,这是我到目前为止对这个问题的理解,如果有任何错误,请指出
首先,在第一个示例中,联合是这样组成的(在globle\u页面前面的local\u addr
)
如果在local\u addr
之前定义了globle\u页面,则布局如下:
############ ##############
# # # #
# g_pointer# # globle_page#
# # # #
############ ##############
##############
# #
# local_addr #
# MSB or LSB #
##############
##############
# #
# local_addr #
# MSB or LSB #
##############
因此,在情况1(local\u addr
在globle\u page
之前定义)中,如果g\u指针的值发生变化,local\u addr
的MSB或LSB也会发生变化,但它为什么要实际添加一个值呢?因为我知道我的平台是Big-Endian字节顺序,所以应该更改local\u addr
的MSB,为什么要更改LSB
在情况2中(globle\u page
在local\u addr
之前定义),我可以解释说g\u指针的值加一,而“globle\u page”的对应地址也加一,但由于情况1,我不太确定这一点
有人能告诉我这里发生的事情的确切答案吗?如果我没有正确描述这个问题,很抱歉我的英语很差
顺便说一句,我使用的平台没有字节对齐问题。因此,sturct是一个字节一个字节写的布局
致以最良好的祝愿,
盛云
首先也是最重要的一点是,结果是未定义的行为。您可能会在不同的编译器中看到不同的结果,甚至在同一个编译器使用不同的选项时也会看到不同的结果。最常见的替代行为是,当您修改一个字段时,其他字段直到将来某个时候才会更改。在过去的表单中,我已经编写了一些测试代码
// assign to the first field
// print the second field
// print the second field
第一次打印显示第二字段的先前值,第二次打印显示第二字段的更新值
除非您真正了解了如何处理别名和未定义的行为,否则决不能以这种方式使用union
s
接下来要知道的是指针很少有1字节长。在大多数现代机器上,它们往往是4或8字节
关于数据布局,接下来要知道的是,有时会填充structs
。对于结构
struct {
char a;
short b;
};
我认为布局很可能是
<one byte of a> <unused byte> <two bytes of b>
作为
我会毫不奇怪地看到
<one byte of a> <3 unused bytes> <two bytes of b>
事实上,根据您的经验结果,我希望您有4字节的指针,最后一种可能性是struct
的实际布局
您可以使用sizeof
和offsetof
函数准确地确定事物sizeof
将告诉您每个类型有多少字节长,而offsetof
将让您确定每个字段在结构或联合中的确切起始位置
另一点需要注意的是,指针的布局并不总是像整数一样。此问题取决于正在运行的计算机体系结构。不过,我认为所有“普通”的人都会像你预期的那样行事
首先也是最重要的一点是,结果是未定义的行为。您可能会在不同的编译器中看到不同的结果,甚至在同一个编译器使用不同的选项时也会看到不同的结果。最常见的替代行为是,当您修改一个字段时,其他字段直到将来某个时候才会更改。在过去的表单中,我已经编写了一些测试代码
// assign to the first field
// print the second field
// print the second field
第一次打印显示第二字段的先前值,第二次打印显示第二字段的更新值
除非您真正了解了如何处理别名和未定义的行为,否则决不能以这种方式使用union
s
接下来要知道的是指针很少有1字节长。在大多数现代机器上,它们往往是4或8字节
关于数据布局,接下来要知道的是,有时会填充structs
。对于结构
struct {
char a;
short b;
};
我认为布局很可能是
<one byte of a> <unused byte> <two bytes of b>
作为
我会毫不奇怪地看到
<one byte of a> <3 unused bytes> <two bytes of b>
事实上,根据您的经验结果,我希望您有4字节的指针,最后一种可能性是struct
的实际布局
您可以使用sizeof
和offsetof
函数准确地确定事物sizeof
将告诉您每个类型有多少字节长,而offsetof
将让您确定每个字段在结构或联合中的确切起始位置
另一点需要注意的是,指针的布局并不总是像整数一样。此问题取决于正在运行的计算机体系结构。不过,我认为所有“普通”成员的行为都与您预期的一样。要进行调查,您可以在联盟中添加一个axtra字段,以检查成员的位置
typedef union {
unsigned char* g_pointer;
struct {
unsigned short local_addr;
unsigned char globle_page;
} g_l;
unsigned char all[ sizeof (unsigned char*)];
} Gld_WordType;
要进行调查,可以向联合中添加axtra字段以检查成员所在的位置
typedef union {
unsigned char* g_pointer;
struct {
unsigned short local_addr;
unsigned char globle_page;
} g_l;
unsigned char all[ sizeof (unsigned char*)];
} Gld_WordType;
问题出在哪里?联合体按照要求与LSB对齐,因此向其中一个联合体添加1
也会向任何其他联合体添加1
,结构体成员的对齐实际上是特定于实现的,但是编译器选择了做一件很明显的事情,就像在你的图片中一样,除了第二个例子中的无符号字符
实际上是一个无符号字符
加1无符号字符
填充。它看起来像是标准的小端点行为。你的平台是什么?“你怎么知道是big endian?”