在C语言中重新解释内存的正确方法是什么?

4

我早已记不清在C语言中类似这样的事情做了多少次:

struct foo f;
struct foo* pf = &f;
char* pc = (char*) pf;
transmit(pc, sizeof(f));

或许应该这样理解:
char* buffer[1024];
receive(buffer, 1024);
float values[256];
for(int ii = 0; ii < 256; ii++) {
    float* pf = (float*)(buffer + ii*4);
    values[ii] = *pf;
}

也许是这样:
uint32_t ipAddress = ...;
uint8_t* p = (uint8_t*)&ipAddress;
uint8_t octets[4] = {p[0], p[1], p[2], p[3]};
printf("%d.%d.%d.%d\n", octets[0], octets[1], octets[2], octets[3]);

我刚刚发现通过将内存重新解释为另一种指针类型来重新解释一块内存会引发未定义的行为。然而,上述所有示例的目的都是绝对必要的。那么正确的做法是什么呢?


1
我可以向您介绍union关键字吗? - Christoph
个人认为,与类型转换相比,使用联合是解决这些问题的更糟糕的方案。需要编写更多的代码,创建更多奇怪的类型,并且仍然需要在各个地方进行强制转换。 - Carl Norum
@Christoph,我不确定我是否明白了 - 使用联合体会有完全相同的问题,对吧?只有在存在对齐问题时,才会导致指针转换发生UB,并非仅仅是将指针强制转换。您当然不能解引用指针,但这是一个不同的步骤 - 类比于访问最近存储到的不同联合成员,这也是未定义的行为。 - Carl Norum
2
@CarlNorum:通过联合体进行类型游戏是完全被定义的(只要你从比你最后写入的成员更短的成员中读取,并且不创建陷阱表示);甚至在C99中有一个脚注告诉你如此。然而,在附录中错误地将其列为UB,这已经在C11中得到了纠正。 - Christoph
@Christoph:如果我指定了strict,我会预料到一些奇怪的行为。我从来没有明确过为什么有人想要剥夺使用指针的好处,因为它们非常有用。但是我也不经常编写应用程序代码。 - user2513931
显示剩余6条评论
1个回答

5
将指针转换为char *(或unsigned char *或其typedef),是一种特殊情况,并且不会导致未定义的行为。
根据C规范,第6.3.2.3节“指针”,第7段:
当将指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节。对结果的连续增量,直到对象的大小,产生指向对象剩余字节的指针。
您的第一个和第三个示例都适用于此情况。第二个示例有点棘手,但在大多数系统上可能可行。您真正应该做的是直接读取values
float values[256];
receive(values, sizeof values); // assuming receive() takes a "void *" parameter

或者像这样(以避免对齐问题):
char buffer[1024];
receive(buffer, sizeof buffer);
float values[256];
for(int i = 0; i < 256; i++)
{
    char *pf = (char *)&values[i];
    memcpy(pf, buffer + i * sizeof(float), sizeof(float));
}

(请注意,我将 buffer 更改为 char 数组-我假设这是您问题中的一个笔误。)

你能提供一个链接吗?我的K&R C书没有这么说...但它不是ISO或ANSI C。 - Mgetz
2
当然,您可以选择C11(PDF链接)C99(PDF链接) - Carl Norum
жҲ‘жҳҜCиҜӯиЁҖзҡ„ж–°жүӢпјҢеҸӘжҳҜжғізҹҘйҒ“char *pf = (char *)&float[i];иҝҷдёҖиЎҢдёӯдҪ еҲ°еә•е°Ҷд»Җд№ҲиҪ¬жҚўдёәдәҶchar *пјҹпјҲжҲ‘зҡ„зј–иҜ‘еҷЁеңЁиҝҷдёҖиЎҢжҠҘй”ҷпјҡparse error before 'float'пјү - qwwqwwq
糟糕,打错了。应该是&values[i]。正在修复。 - Carl Norum
@qwwqwwq:这是一个打字错误。将“float”更改为“values”。 - jxh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接