gpt4 book ai didi

c++ - 如何用 0 memset 匿名 union

转载 作者:可可西里 更新时间:2023-11-01 16:01:05 25 4
gpt4 key购买 nike

我应该如何将匿名 union 归零?我在 cppreference 上找不到任何内容关于它的页面。 memset它最大的成员 0 在这里工作吗?

例如-

#include <iostream>
#include <cstring>

struct s{
char a;
char b[100];
};

int main(){
union {
int a;
s b;
char c;
};

// b.a = 'a'; (1)

std::memset(&b, 0, sizeof(b));

std::cout << a << "\n";
std::cout << b.a << " " << b.b << "\n";
std::cout << c << "\n";
}

此外,如果这行得通,我是否应该在使用 memset() 激活最大成员之前取消注释 (1)?

最佳答案

如果你真的想尊重标准,你应该知道你写的代码是未定义的行为:C++标准§3.8 [basic.life]:

... except that if the object is a union member or subobject thereof, its lifetime only begins if that union member is the initialized member in the union (8.6.1, 12.6.2), or as described in 9.3. The lifetime of an object o of type T ends when: (1.3) — if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or (1.4) — the storage which the object occupies is released, or is reused by an object that is not nested within o (1.8).

在 §9.3 中解释了您可以通过分配给标准布局 union 的成员来激活它。它还解释了您可以探索 union 成员的值(value),该 union 只有在满足某些条件时才会被激活:

If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if a non-static data member of an object of this standard-layout union type is active and is one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of the standard-layout struct members; see 9.2. — end note ]

所以当你写std::cout<< a << "\n"你还没有初始化a ,或通过赋值激活它,并且没有成员被初始化,所以你处于未定义的行为(注意:但我知道的编译器支持它,至少在 PC 上,作为标准的扩展。 )

所以在使用之前a你必须写a=0 , 或制作 a union 的初始化成员,因为a不与 b 共享公共(public)初始化序列也不c .

所以如果你使用memset 正如 MSalters 的回答中所建议的,无论您做什么,您都必须在使用之前将某些东西分配给 union 成员。如果想保持定义的行为,请不要使用 memset .注意 memset可以安全地与非 union 成员的标准布局对象一起使用,因为它们的生命周期从为它们获取存储时开始。


总而言之,要保持已定义的行为,您必须至少初始化一个成员,然后您可以检查 union 体中与初始化成员共享公共(public)初始化序列的其他成员。

  1. 如果您打算在主函数中使用匿名 union ,您可以声明 union 静态:所有静态对象都是零初始化的。 (但当您记忆起 main() 不会发生的功能时,不会重新初始化):

    int main(){
    static union {
    s b;
    int a;
    char c;
    };
    //...
    }

    如 C++ 标准 §8.6 文章 (6.3) [dcl.init] 中所述:

    if T is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero- initialized and padding is initialized to zero bits;

  2. 否则,如果结构成员 (s) 之间没有填充,则可以使用空列表聚合初始化较大的成员 (s):

    //...
    int main(){
    union {
    int a;
    s b{};
    char c;
    };
    //...
    }

    之所以可行,是因为 union 的所有成员都是一致的。因此,如果 s 的成员之间没有填充, union 内存的每个字节都将初始化为零,C++ 标准 §9.3 [class.union] 第 2 条:

    The size of a union is sufficient to contain the largest of its non-static data members. Each non-static data member is allocated as if it were the sole member of a struct. [ Note: A union object and its non-static data members are pointer-interconvertible (3.9.2, 5.2.9). As a consequence, all non-static data members of a union object have the same address.

  3. 如果S内部有padding,那么就声明一个char数组来初始化:

    //...
    int main(){
    union {
    char _initialization[sizeof(s)]{};
    int a;
    s b;
    char c;
    };
    //...
    }

注意:使用您的示例,或最后两个代码示例,以及使用 memset 的代码生成完全相同的初始化指令集(clang -> x86_64):

    pushq   %r14
pushq %rbx
subq $120, %rsp
xorps %xmm0, %xmm0
movaps %xmm0, 96(%rsp)
movaps %xmm0, 80(%rsp)
movaps %xmm0, 64(%rsp)
movaps %xmm0, 48(%rsp)
movaps %xmm0, 32(%rsp)
movaps %xmm0, 16(%rsp)
movq $0, 109(%rsp)

关于c++ - 如何用 0 memset 匿名 union ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42361656/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com