无法理解这个联盟

时间:2012-03-09 10:39:05

标签: 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;
    } 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

好的,这是我对这个问题的理解,直到现在,如果有任何错误,请指出。

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是逐字节写的布局。

最诚挚的问候, 盛云

2 个答案:

答案 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的实际布局。

您可以使用sizeofoffsetof函数来准确判断事物。 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;