3

假设我有来自外部库的以下类型:

union foreign_t {
    struct {
        enum enum_t an_enum;
        int an_int;
    } header;
    struct {
        double x, y;
    } point;
};

假设以下代码片段将在不同平台和不同编译器上按预期工作是否安全?

struct pair_t {
    double x, y;
};

union foreign_t foreign;
struct pair_t *p_pair;

p_pair = (struct pair_t *) &foreign;
p_pair->x = 1234;
p_pair->y = 4321;

/* Expected result: (1234, 4321) or something like that */
printf("(%lf, %lf)", foreign.point.x, foreign.point.y);

编辑:

按照严格的别名建议,我做了以下测试:

#include <stdint.h>
#include <stdio.h>

int main()
{
    uint16_t word = 0xabcd;
    uint8_t tmp;
    struct {
        uint8_t low;
        uint8_t high;
    } *byte = (void *) &word;

    tmp = byte->low;
    byte->low = byte->high;
    byte->high = tmp;

    printf("%x\n", word);

    return 0;
}

上面这段看似无辜的代码并不可靠:

$ gcc -O3 -fno-strict-aliasing -otest test.c
$ ./test
cdab
$ gcc -O3 -fstrict-aliasing -otest test.c
$ ./test
abcd

开发商没有安宁...

4

8 回答 8

6

正如您所写的那样,我相信它几乎可以与任何架构上的任何编译器一起使用。但是,我确实认为它在技术上违反了严格的别名规则。您在不相关的指针类型之间进行转换,因此过于激进的优化器可能会重新排序某些内存读取和写入,因为它假定某些指针不会相互别名。

不幸的是,假设您不能修改foreign_t. 由于内部结构没有名称,因此您无法构造指向它的指针,编译器将假定它是可别名的。不过,在实践中,我认为您不会发现代码有问题。

于 2009-10-16T00:59:08.470 回答
2

是的,它应该是完全便携的。联合的事实foreign甚至从未涉及到它,因为您从未将其用作header.

(你不能写入header然后读取point并期望它在所有平台上都一样工作。但是,你不想这样做,所以你应该没问题。)

于 2009-10-15T22:07:02.923 回答
2

是的,这是完全合理的。ANSI C 标准表明您不应该将一种“类型”写入联合并读出另一种并期望得到可靠的东西,期望在非常特定的情况下。在这里,您想以一种方式将某些内容写入联合,然后以相同的方式将其读出。保证在联合开始时没有填充,并且有适当的指针对齐,所以据我了解,你应该对此很好。

于 2009-10-15T22:07:30.740 回答
1

是的,这将正常工作。但是,一旦您写了foreign.header所有关于 的内容的赌注foreign.point,即使特定操作适用于给定的编译器。

于 2009-10-15T22:04:43.953 回答
1

是的,您可以保证相同的结构具有相同的大小和对齐要求。

于 2009-10-15T22:30:17.287 回答
1

如所写,是的,它可以在任何单一平台上按您期望的方式工作。

一个更典型的定义是将包含类型鉴别器字段的 aforeign包装起来,以便在运行时为该类型的每个值显式地知道联合的有效分支。unionstruct

有趣的地方是当您希望将 a 的值foreign从平台 A 传达给平台 B 并再次获取预期数据时。在那里,您至少会遇到对齐、大小和字节顺序差异,甚至可能是数字表示差异,因为标准实际上并不需要 IEEE 浮点数或 2 的补码二进制整数。

在实践中,情况并没有那么糟糕,但它成为了可移植性的一个关注点,如果需要二进制交换格式,最好通过特定于平台的测试用例和/或编译时断言来缓解这一问题。

或者,将来自特定平台的数据编组struct或编组union到定义良好的八位字节序列中以进行存储和传输是可靠的答案。例如,这是 MPEG 标准所采用的方法。

于 2009-10-16T00:39:54.047 回答
0

假设double, int, 并enum保持一致性(我不会发誓,但我相信这double是 IEEE 标准),它应该可靠地工作。但是,int根据系统字的不同而变化enum,据所知,不能依赖特定的大小。

于 2009-10-15T22:12:04.250 回答
-1

假设以下代码片段将在不同平台和不同编译器上按预期工作是否安全?

简单的答案是否定的...

对于每台机器和编译器,您需要找出正确对齐结构的命令,这是主要的可移植性问题之一

于 2009-10-20T00:20:32.177 回答