我在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_addrgloble_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

好的,这是我到现在为止对这个问题的理解,如果有什么问题,请指出。
第一,在第一个例子中,union是这样组成的(前面的local_addr
############  #############
#          #  #           #
# g_pointer#  # local_addr#
#          #  # MSB or LSB#
############  #############
              #############
              #           #
              # local_addr#
              # MSB or LSB#
              #############
              ##############
              #            #
              # globle_page#
              #            #
              ##############

如果globle_page是在globle_page之前定义的,则布局如下:
############  ##############
#          #  #            #
# g_pointer#  # globle_page#
#          #  #            #
############  ##############
              ##############
              #            #
              # local_addr #
              # MSB or LSB #
              ##############
              ##############
              #            #
              # local_addr #
              # MSB or LSB #
              ##############

因此,在情况1(local_addr定义在local_addr之前)中,如果globle_page的值更改,g_pointer的MSB或LSB也将更改,但为什么它实际上要添加一个呢?因为我知道我的平台是大端字节顺序,所以应该更改local_addr的MSB,为什么要更改LSB?
在第二种情况下(local_addrgloble_page之前定义),我可以解释local_addr的值加了一个,而对应的“globle_page”地址也加了一个,但是由于第一种情况,我对此不太确定。
有人能告诉我这里发生的事情的确切答案吗?如果我没有恰当地描述这个问题,我的英语很差。
顺便说一下,我使用的平台没有字节对齐问题。所以struct是按写的顺序逐字节布局的。
谨致问候,
盛运

最佳答案

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

第一次打印显示第二个字段的前一个值,第二次打印显示第二个字段的更新值。
在您真正了解有关别名和未定义行为的操作之前,不应以这种方式使用unions。
接下来要知道的是指针很少有1字节长。在大多数现代机器上,它们往往是4或8字节。
关于数据布局,接下来要知道的是有时会填充structs。对于结构
struct {
    char a;
    short b;
};

我认为布局很可能是
<one byte of a>  <unused byte>  <two bytes of b>

作为
<one byte of a>  <two bytes of b>

我会毫不惊讶地看到
<one byte of a>  <3 unused bytes>  <two bytes of b>

事实上,根据你的经验结果,我认为你有4字节的指针,最后一个可能性是struct是如何实际布局的。
您可以使用sizeofoffsetof函数精确地确定事情。sizeof将告诉您每种类型的长度为多少字节,offsetof将让您确定结构或联合中每个字段的起始位置。
需要注意的另一点是指针的布局并不总是像整数一样。此问题取决于您运行的计算机体系结构。不过,我认为所有“普通”的人都会像你期望的那样。

10-08 02:40