我在ideone.com上尝试了这段代码,它符合,但我无法解释发生了什么,任何帮助都会很棒:)
这是代码:
#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;
}
结果是:
g_pointer: 13fff0
local_addr: fff0
globle_page: 13
g_pointer: 13fff1
local_addr: fff1
globle_page: 13
如果我只是改变local_addr
和globle_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: fff00013
local_addr: fff0
globle_page: 13
g_pointer: fff00014
local_addr: fff0
globle_page: 14
好的,这是我对这个问题的理解,直到现在,如果有任何错误,请指出。
1,在第一个例子(local_addr
前面的globle_page
)
############ #############
# # # #
# g_pointer# # local_addr#
# # # MSB or LSB#
############ #############
#############
# #
# local_addr#
# MSB or LSB#
#############
##############
# #
# globle_page#
# #
##############
如果在globle_page
:
local_addr
,则布局如下所示
############ ##############
# # # #
# g_pointer# # globle_page#
# # # #
############ ##############
##############
# #
# local_addr #
# MSB or LSB #
##############
##############
# #
# local_addr #
# MSB or LSB #
##############
所以情况1(local_addr
之前定义的globle_page
),如果g_pointer
的值变化,local_addr
的MSB或LSB也会改变,但为什么是它实际上加了一个?因为我知道我的平台是Big-Endian字节顺序,所以应该改变local_addr
的MSB,为什么LSB会改变?
在情境2(globle_page
之前定义的local_addr
)中,我可以解释g_pointer
的值加1,而'globle_page'的相应地址也会添加一个,但是因为情况1,我不太确定这一点。
谁能告诉我这里发生的事情的确切答案?如果我没有正确描述这个问题,对不起我的英语很差。
顺便说一下,我正在使用的平台没有字节对齐问题。所以sturct是逐字节写的布局。最诚挚的问候, 盛云
答案 0 :(得分:1)
could anyone tell me the exact answer of what is happening here?
首先要知道的是,结果是未定义的行为。您可能会看到不同编译器的不同结果 - 甚至使用不同选项的相同编译器。最常见的替代行为是,当您修改一个字段时,其他字段在将来的某个时间内不会更改。我在表格的过去编写了一些测试代码
// assign to the first field
// print the second field
// print the second field
,第一个打印显示第二个字段的前一个值,第二个打印显示第二个字段的更新值。
在您真正了解您在别名和未定义行为方面所做的工作之前,您应该从不以这种方式使用union
。
接下来要知道的是指针很少有1个字节长。在大多数现代机器上,它们往往是4或8个字节。
接下来要了解的数据布局是有时会填充structs
。对于struct
struct {
char a;
short b;
};
我认为布局很可能
<one byte of a> <unused byte> <two bytes of b>
as
<one byte of a> <two bytes of b>
我不会惊讶地看到
<one byte of a> <3 unused bytes> <two bytes of b>
事实上,根据你的实证结果,我希望你有4字节的指针,最后一种可能性就是struct
的实际布局。
您可以使用sizeof
和offsetof
函数来准确判断事物。 sizeof
会告诉您每种类型的字节长度,offsetof
可以让您确定每个字段的结构或联合中的确切位置。
需要注意的另一点是指针不像整数一样总是布局。此问题取决于您运行的计算机体系结构。我认为所有“普通”的行为都与你期望的一样。
答案 1 :(得分:0)
要进行调查,您可以在联合中添加一个额外的字段,以检查成员的位置。
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;