首页 文章

结构与联盟之间的区别

提问于
浏览
368

是否有任何好的例子来区分 structunion ?基本上我知道 struct 使用其成员的所有内存而 union 使用最大的成员内存空间 . 是否有其他操作系统级别的差异?

15 回答

  • 1

    这是简短的回答:结构是一个记录结构:结构中的每个元素分配新的空间 . 所以,像一个结构

    struct foobarbazquux_t {
        int foo;
        long bar;
        double baz; 
        long double quux;
    }
    

    为每个实例在内存中分配至少 (sizeof(int)+sizeof(long)+sizeof(double)+sizeof(long double)) 个字节 . ("At least"因为体系结构对齐约束可能会强制编译器填充结构 . )

    另一方面,

    union foobarbazquux_u {
        int foo;
        long bar;
        double baz; 
        long double quux;
    }
    

    分配一块内存并给它四个别名 . 所以 sizeof(union foobarbazquux_u) ≥ max((sizeof(int),sizeof(long),sizeof(double),sizeof(long double)) ,再次有可能增加一些路线 .

  • 3

    有没有什么好的例子来区分'struct'和'union'?

    一种虚构的通信协议

    struct packetheader {
       int sourceaddress;
       int destaddress;
       int messagetype;
       union request {
           char fourcc[4];
           int requestnumber;
       };
    };
    

    在这个虚构协议中,已经指定基于“消息类型”, Headers 中的以下位置将是请求号或四字符代码,但不是两者 . 简而言之,工会允许相同的存储位置代表多种数据类型,在此保证您只想在任何时候存储一种类型的数据 .

    工会在很大程度上是基于C作为系统编程语言的传统的低级细节,其中“重叠”存储位置有时以这种方式使用 . 有时您可以使用联合来节省内存,其中您拥有一个数据结构,其中一次只能保存多种类型中的一种 .

    一般来说,操作系统并不关心或了解结构和联合 - 它们都只是简单的内存块 . 结构是一个存储器块,用于存储多个数据对象,这些对象不会重叠 . union是一个存储多个数据对象的内存块,但只有最大的存储块,因此任何时候都只能存储一个数据对象 .

  • 1

    使用union,你只能使用其中一个元素,因为它们都存储在同一个地方 . 当您想要存储可能是多种类型之一的东西时,这会很有用 . 另一方面,结构为每个元素都有一个单独的内存位置,它们都可以一次使用 .

    为了给出它们的使用的具体示例,我不久前在使用Scheme解释器,我基本上将Scheme数据类型覆盖到C数据类型上 . 这涉及在结构中存储指示值类型的枚举和存储该值的联合 .

    union foo {
      int a;   // can't use both a and b at once
      char b;
    } foo;
    
    struct bar {
      int a;   // can use both a and b simultaneously
      char b;
    } bar;
    
    union foo x;
    x.a = 3; // OK
    x.b = 'c'; // NO! this affects the value of x.a!
    
    struct bar y;
    y.a = 3; // OK
    y.b = 'c'; // OK
    

    edit: 如果你're wondering what setting x.b to ' c ' changes the value of x.a to, technically speaking it'未定义 . 在大多数现代机器上,char是1个字节,int是4个字节,因此给x.b赋值'c'也给x.a的第一个字节赋予相同的值:

    union foo x;
    x.a = 3;
    x.b = 'c';
    printf("%i, %i\n", x.a, x.b);
    

    版画

    99, 99
    

    为什么两个值相同?因为int 3的最后3个字节都是零,所以它也被读为99.如果我们为x.a输入一个更大的数字,你会发现情况并非总是这样:

    union foo x;
    x.a = 387439;
    x.b = 'c';
    printf("%i, %i\n", x.a, x.b);
    

    版画

    387427, 99
    

    为了更仔细地查看实际的内存值,让我们设置并打印出十六进制的值:

    union foo x;
    x.a = 0xDEADBEEF;
    x.b = 0x22;
    printf("%x, %x\n", x.a, x.b);
    

    版画

    deadbe22, 22
    

    你可以清楚地看到0x22覆盖了0xEF的位置 .

    BUT

    在C中,int中的字节顺序是 not defined. 这个程序在我的Mac上用0x22覆盖了0xEF,但是还有其他平台会覆盖0xDE,因为构成int的字节顺序是相反的 . 因此,在编写程序时,不应该依赖于在联合中覆盖特定数据的行为,因为它不可移植 .

    有关字节顺序的更多读数,请查看endianness .

  • 10

    结构是不同数据类型的集合,其中不同类型的数据可以驻留在其中,并且每个数据类型都有自己的内存块

    当我们确定只有一个变量将被立即使用并且你想要充分利用当前内存时,我们通常使用union,因为它只获得一个内存块,它等于最大类型 .

    struct emp
    {
        char x;//1 byte
        float y; //4 byte
    } e;
    

    它获得的总内存=> 5字节

    union emp
    {
        char x;//1 byte
        float y; //4 byte
    } e;
    

    它获得的总内存= 4字节

  • 614

    正如您在问题中已经说明的那样, unionstruct 之间的主要区别在于 union 成员覆盖了彼此的内存,因此联合的sizeof是一个,而 struct 成员一个接一个地布局(使用可选的填充)介于两者之间) . 联合也足够大以包含其所有成员,并且具有适合其所有成员的对齐 . 所以假设 int 只能存储在2字节地址并且是2字节宽,而long只能存储在4字节地址并且长度为4字节 . 以下联盟

    union test {
        int a;
        long b;
    };
    

    可以有 sizeof 为4,对齐要求为4. union和struct都可以在末尾有填充,但不能在它们的开头 . 写入结构只会更改写入的成员的值 . 写入联合成员将使所有其他成员的值无效 . 如果您最近没有写入它们,则无法访问它们 . 对于操作系统,用户程序是写入联合还是结构并不重要 . 这实际上只是编译器的一个问题 .

    union和struct的另一个重要属性是,它们允许指向它们的指针指向其任何成员的类型 . 所以以下是有效的:

    struct test {
        int a;
        double b;
    } * some_test_pointer;
    

    some_test_pointer可以指向 int*bool* . 如果将 test 类型的地址强制转换为 int* ,它实际上将指向其第一个成员 a . 工会也是如此 . 因此,因为联合将始终具有正确的对齐,您可以使用联合来指向某些类型的有效:

    union a {
        int a;
        double b;
    };
    

    该联合实际上可以指向一个int和一个double:

    union a * v = (union a*)some_int_pointer;
    *some_int_pointer = 5;
    v->a = 10;
    return *some_int_pointer;
    

    实际上是有效的,如C99标准所述:

    对象的存储值只能由具有以下类型之一的左值表达式访问:与对象的有效类型兼容的类型...在其成员中包含上述类型之一的聚合或联合类型

    编译器不会优化 v->a = 10; ,因为它可能会影响 *some_int_pointer 的值(并且该函数将返回 10 而不是 5 ) .

  • 11

    union 在几个场景中很有用 . union 可以是非常低级操作的工具,例如为内核编写设备驱动程序 .

    一个例子是使用带有位域 floatstruct 来解析 float 数字 . 我在 float 中保存了一个数字,之后我可以通过 struct 访问 float 的特定部分 . 该示例显示了 union 如何使用不同的角度来查看数据 .

    #include <stdio.h>                                                                                                                                       
    
    union foo {
        struct float_guts {
            unsigned int fraction : 23;
            unsigned int exponent : 8;
            unsigned int sign     : 1;
        } fg;
        float f;
    };
    
    void print_float(float f) {
        union foo ff;
        ff.f = f;
        printf("%f: %d 0x%X 0x%X\n", f, ff.fg.sign, ff.fg.exponent, ff.fg.fraction);
    
    }
    
    int main(){
        print_float(0.15625);
        return 0;
    }
    

    看看维基百科上的single precision描述 . 我用那个例子和幻数0.15625 .


    union 也可用于实现具有多个备选方案的代数数据类型 . 我在O'Sullivan,Stewart和Goerzen的书中找到了一个例子 . 请在The discriminated union部分查看 .

    干杯!

  • 48

    union " and " struct ”是C语言的构造 . 谈论它们之间的区别是不合适的,因为如果您使用一个或另一个关键字,编译器会产生不同的代码 .

  • 2

    从技术上讲,这意味着:

    假设:主席=内存块,人=变量

    Structure :如果有3个人,他们可以相应地坐在椅子上 .

    Union :如果有3个人 only one 椅子会在那里坐下,所有人都需要在他们想坐的时候使用同一把椅子 .

    从技术上讲,意味着:

    下面提到的计划深入探讨了结构和联合 .

    struct MAIN_STRUCT
    {
    UINT64 bufferaddr;   
    union {
        UINT32 data;
        struct INNER_STRUCT{
            UINT16 length;  
            UINT8 cso;  
            UINT8 cmd;  
               } flags;
         } data1;
    };
    

    用于填充32位的bufferaddr sizeof(UNIT32)的总MAIN_STRUCT大小= sizeof(UINT64)(取决于处理器架构)= 128位 . 对于结构,所有成员都连续获取内存块 .

    Union获取max size成员的一个内存块(这里是32位) . 在内部联合中,还有一个结构(INNER_STRUCT)其成员获得总大小为32位(16 8 8)的内存块 . 在联合中,可以访问INNER_STRUCT(32位)成员 or 数据(32位) .

  • 11

    是的,struct和union之间的主要区别与你所说的相同 . Struct使用其成员的所有内存和union使用最大的成员内存空间 .

    但所有不同之处在于内存的使用需求 . 在我们利用信号的unix过程中可以看到联合的最佳用法 . 就像一个过程一次只能对一个信号起作用 . 所以一般声明将是:

    union SIGSELECT
    {
      SIGNAL_1 signal1;
      SIGNAL_2 signal2;
      .....
    };
    

    在这种情况下,进程仅使用所有信号的最高内存 . 但如果在这种情况下使用struct,则内存使用量将是所有信号的总和 . 造成很大的不同 .

    总而言之,如果您知道一次访问任何一个成员,则应选择Union .

  • 38

    你拥有它,就是这样 . 但基本上,工会有什么意义呢?

    您可以在不同类型的相同位置放置内容 . 你必须知道你在联合中存储的内容的类型(通常你把它放在带有类型标记的 struct 中......) .

    为什么这很重要?不是为了空间收益 . 是的,你可以获得一些比特或做一些填充,但这不再是主要观点了 .

    它是为了类型安全,它使您能够进行某种“动态类型化”:编译器知道您的内容可能具有不同的含义以及您在运行时如何解释它的确切含义 . 如果你有一个可以指向不同类型的指针,你必须使用一个联合,否则你的代码可能由于别名问题而不正确(编译器对自己说“哦,只有这个指针可以指向这种类型,所以我可以优化那些访问......“,可能会发生坏事 . ”

  • 76

    结构分配其中所有元素的总大小 .

    联合只分配与其最大成员所需的内存一样多的内存 .

  • 3

    当需要专门的类型对话时,经常使用union Unions . 了解工会的用处 . c / c标准库没有定义专门设计用于将短整数写入文件的函数 . 使用fwrite()导致简单操作会产生过多的开销 . 但是,使用联合,您可以轻松创建一个函数,该函数一次将一个短整数的二进制写入文件 . 我假设短整数长2个字节

    这个例子:

    #include<stdio.h>
    union pw {
    short int i;
    char ch[2];
    };
    int putw(short int num, FILE *fp);
    int main (void)
    {
    FILE *fp;
    fp fopen("test.tmp", "wb ");
    putw(1000, fp); /* write the value 1000 as an integer*/
    fclose(fp);
    return 0;
    }
    int putw(short int num, FILE *fp)
    {
    pw word;
    word.i = num;
    putc(word.c[0] , fp);
    return putc(word.c[1] , fp);
    }
    

    虽然putw()我用短整数调用,但是可以使用putc()和fwrite() . 但我想举例说明如何使用联盟

  • 17

    结构和联盟有什么区别?

    捷径答案是:顺从是内存分配 . 说明:在结构中,将为结构内的所有成员创建内存空间 . 在union中,将仅为需要最大内存空间的成员创建内存空间 . 请考虑以下代码:

    struct s_tag
    {
       int a; 
       long int b;
    } x;
    
    union u_tag
    {
       int a; 
       long int b;
    } y;
    

    这里有struct和union中的两个成员:int和long int . int的内存空间为:4字节,long int的内存空间为:32位操作系统中的8 .

    因此对于struct 4 8 =将创建12个字节,同时将为union创建8个字节

    代码示例:

    #include<stdio.h>
    struct s_tag
    {
      int a;
      long int b;
    } x;
    union u_tag
    {
         int a;
         long int b;
    } y;
    int main()
    {
        printf("Memory allocation for structure = %d", sizeof(x));
        printf("\nMemory allocation for union = %d", sizeof(y));
        return 0;
    }
    

    参考:http://www.codingpractise.com/home/c-programming/structure-and-union/

  • 11

    在编写下面给出的字节排序函数时,联合会很方便 . 结构不可能 .

    int main(int argc, char **argv) {
        union {
            short   s;
            char    c[sizeof(short)];
        } un;
    
        un.s = 0x0102;
    
        if (sizeof(short) == 2) {
            if (un.c[0] == 1 && un.c[1] == 2)
                printf("big-endian\n");
            else if (un.c[0] == 2 && un.c[1] == 1)
                printf("little-endian\n");
            else
                printf("unknown\n");
        } else
            printf("sizeof(short) = %d\n", sizeof(short));
    
        exit(0);
    }
    // Program from Unix Network Programming Vol. 1 by Stevens.
    
  • 9

    联盟不同于结构,因为联盟重复其他结构:它重新定义相同的内存,而结构定义一个接一个,没有重叠或重新定义 .

相关问题