当询问C中常见的未定义行为时,灵魂比我提到的严格别名规则更加开明.
他们在说什么?
在使用-O1和-O2(包括gcc和clang)编译后,此代码打印不同的值:
#include <stdio.h>
static void check (int *h, long *k)
{
*h = 5;
*k = 6;
printf("%d\n", *h);
}
union MyU
{
long l;
int i;
};
int main (void)
{
union MyU u;
check(&u.i, &u.l);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我认为它应该是未定义的行为,因为指针别名,但我无法确切地指出代码的哪一部分是被禁止的.
它写入一个union元素然后从另一个读取,但是根据允许的缺陷报告#283.通过指针而不是直接访问union元素时是UB吗?
这个问题类似于通过指针访问C联盟成员,但我认为其中一个从未得到完全回答.
鉴于以下代码,我有一些与类型双关相关的问题。我看不出这没有违反严格的别名规则,但我无法指出具体的违规行为。我最好的猜测是,将联合成员传递到函数中违反了严格的别名。
以下代码位于Compiler Explorer上。
#include <stdint.h>
union my_type
{
uint8_t m8[8];
uint16_t m16[4];
uint32_t m32[2];
uint64_t m64;
};
int func(uint16_t *x, uint32_t *y)
{
return *y += *x;
}
int main(int argc, char *argv[])
{
union my_type mine = {.m64 = 1234567890};
return func(mine.m16, mine.m32);
}
Run Code Online (Sandbox Code Playgroud)
我的观察:
func不互相别名,func则不违反严格别名。unionfor 类型双关。m16和m32进入func必须违反某些内容。我的问题:
func?注意:学习严格的别名规则。请耐心等待。
代码示例(t935.c):
#include <stdio.h>
int f(int* pi, double* pd)
{
*pi = 13;
*pd = 7E-323;
return *pi;
}
int main(void)
{
union { int i; double d; } u;
printf("%d\n", f(&u.i, &u.d));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
调用:
$ gcc t935.c -Wall -Wextra -std=c11 -pedantic && ./a.exe
14
$ gcc t935.c -Wall -Wextra -std=c11 -pedantic -O2 && ./a.exe
13
$ gcc t935.c -Wall -Wextra -std=c11 -pedantic -O2 -fno-strict-aliasing && ./a.exe
14
Run Code Online (Sandbox Code Playgroud)
问题:将指向同一联合成员的两个指针传递给函数是否违反了严格的别名规则?
这个问题源于Unions 和 type-punning。
UPD20210901
如果在全局范围内定义联合类型会发生什么?
对于“u …