gpt4 book ai didi

c - 这种对 union 行为的解释是正确的吗?

转载 作者:太空宇宙 更新时间:2023-11-04 04:28:59 24 4
gpt4 key购买 nike

^^^这个问题不是关于双关语^^^
我的理解是,包含在联合中的对象只能在它处于活动状态时使用,并且如果它是最后一个存储值的成员,则它是活动的。这意味着在我标记的点上应该未定义以下代码。
我的问题是,我是否正确理解什么时候定义访问工会成员,特别是在以下情况下。

#include <stddef.h>
#include <stdio.h>

void work_with_ints(int* p, size_t k)
{
size_t i = 1;
for(;i<k;++i) p[i]=p[i-1];
}

void work_with_floats(float* p, size_t k)
{
size_t i = 1;
for(;i<k;++i) p[i]=p[i-1];
}

int main(void)
{

union{ int I[4]; float F[4]; } u;

// this is undefined because no member of the union was previously
// selected by storing a value to the union object
work_with_ints(u.I,4);
printf("%d %d %d %d\n",u.I[0],u.I[1],u.I[2],u.I[3]);

u.I[0]=1; u.I[1]=2; u.I[2]=3; u.I[3]=4;

// this is undefined because u currently stores an object of type int[4]
work_with_floats(u.F,4);
printf("%f %f %f %f\n",u.F[0],u.F[1],u.F[2],u.F[3]);

// this is defined because the assignment makes u store an object of
// type F[4], which is subsequently accessed
u.F[0]=42.0;
work_with_floats(u.F,4);
printf("%f %f %f %f\n",u.F[0],u.F[1],u.F[2],u.F[3]);

return 0;
}

我所记的三项内容对吗?
由于大小的关系,这里无法使用我的实际示例,但在一条注释中建议将此示例扩展到可编译的内容。我在clang(-Weverything-std=c11)和gcc(-pedantic-std=c11)中编译并运行了上面的代码。每个人都给出了以下信息:
0 0 0 0
0.000000 0.000000 0.000000 0.000000
42.000000 42.000000 42.000000 42.000000

这似乎是合适的,但这并不意味着代码是兼容的。
编辑:
为了澄清代码的作用,我将指出我在第一段中提到的属性应用的确切实例。
首先,读取和修改未初始化联合的内容。如果我在第一段中提到的原则是正确的,这是未定义的行为,而不是未指定的具有陷阱的UB的可能性。
其次,联合的内容与非活动联合成员的类型一起使用。同样,如果我在第一段中提到的原则是正确的,这是未定义的行为,而不是未指定的具有陷阱的UB的可能性。
第三,如果修改了非活动成员中包含的数组的第一个元素,则刚才提到的“second”项会产生未指定的行为,并可能导致带有陷阱的UB。这使得整个数组成为活动成员,从而改变了定义。
我在这个问题的第一段中演示这个原则的后果,以说明这个原则如果正确的话,如何影响C标准的性质。由于在某些情况下对本标准的性质产生了重大影响,我正在寻求帮助,以确定我所陈述的原则是否正确理解本标准。
编辑:
我认为这可能有助于描述我如何从标准中获得上述第一段中的原则,以及人们如何可能不同意。标准中对这件事说得不多,所以不管怎样都要有一些补缺。
标准将联合描述为一次持有一个对象。这似乎意味着将其视为包含一个元素的结构。似乎任何偏离这种解释的地方都值得一提。这就是我如何达到我所说的原则。
另一方面,关于有效类型的讨论并没有界定“声明类型”一词。如果该术语被理解为联合成员没有声明的类型,那么可以认为联合的每个子对象都需要递归地解释为另一个成员。所以,在我的代码的最后一个例子中,所有浮点数组成员都需要初始化,而不仅仅是第一个。
我举的两个未定义行为的例子对我来说很重要。然而,最后一个例子与上述段落有关,似乎最为关键。不管怎样,我都能看到争论。
编辑:
这不是一个典型的双关语问题。首先,我说的是给工会写信,而不是给他们读书。第二,我在讨论用指针而不是联合类型进行这些写操作的有效性。这与类型双关语问题非常不同。
这个问题与严格的别名有关,而不是与类型双关语有关。由于严格的别名,您无法访问所需的内存。这个问题涉及的正是工会如何减轻对其成员严格别名的限制。没有人说他们会那样做,但如果他们不这样做,你就永远不能做如下事情。
union{int i} u; u.i=0; function_working_with_an_int_pointer (&u.i);

因此,很明显,在某些情况下,联合会会影响严格别名规则的应用。我的问题是确认我根据我对标准的阅读所画的线是正确的。

最佳答案

只有当联合中包含的对象处于活动状态,并且如果它是最后一个向其存储值的成员,则该对象才可用。
这句话是假的。行为是可靠的和明确的。

  union {
unsigned char c [4];
long d;
} v;

v .d = 0xaabbccddL;

printf ("%x\n", v .c [2]);

访问 c成员是完全可以接受的,即使它不是最后分配的成员。在一个小的endian机器上,它肯定会显示 bb,在一个大的endian机器上, cc

关于c - 这种对 union 行为的解释是正确的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38494249/

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