我想以便携方式(C99)将一种类型的数据重新解释为另一种类型.我不是在谈论铸造,我想重新解释一些给定的数据.此外,通过便携式我的意思是它不会破坏C99规则 - 我并不是说重新解释的值在所有系统上都是相同的.
我知道3种不同的重新解释数据的方法,但其中只有两种是可移植的:
这不是便携式的 - 它打破了严格的别名规则.
/* #1 Type Punning */
float float_value = 3.14;
int *int_pointer = (int *)&float_value;
int int_value = *int_pointer;
Run Code Online (Sandbox Code Playgroud)这是依赖于平台的,因为它int在写入之后从联合中读取值float.但它不会破坏任何C99规则,所以它应该工作(如果sizeof(int) == sizeof(float)).
/* #2 Union Punning */
union data {
float float_value;
int int_value;
};
union data data_value;
data_value.float_value = 3.14;
int int_value = data_value.int_value;
Run Code Online (Sandbox Code Playgroud)应该没问题,只要 sizeof(int) == sizeof(float)
/* #3 Copying */
float float_value = 3.14;
int int_value = …Run Code Online (Sandbox Code Playgroud)在使用-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联盟成员,但我认为其中一个从未得到完全回答.
注意:学习严格的别名规则。请耐心等待。
代码示例(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 …
基本上,我有一个
struct foo {
/* variable denoting active member of union */
enum whichmember w;
union {
struct some_struct my_struct;
struct some_struct2 my_struct2;
struct some_struct3 my_struct3;
/* let's say that my_struct is the largest member */
};
};
main()
{
/*...*/
/* earlier in main, we get some struct foo d with an */
/* unknown union assignment; d.w is correct, however */
struct foo f;
f.my_struct = d.my_struct; /* mystruct isn't necessarily the */
/* active member, but is …Run Code Online (Sandbox Code Playgroud)