can';我不理解这个联盟

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;

我在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;
}
如果我简单地切换
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?”