【问题标题】:What's the right way to reinterpret memory in C?在 C 中重新解释内存的正确方法是什么?
【发布时间】:2013-06-27 16:47:30
【问题描述】:

很久以前,我已经记不清我在 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]);

我刚刚发现通过转换为另一种指针类型来重新解释这样的一段内存会调用未定义的行为。然而,上面所有的例子都是绝对必要的。正确的做法是什么?

【问题讨论】:

  • 我可以让您对union 关键字感兴趣吗?
  • 就个人而言,我认为对于这些问题,使用联合是比类型转换更糟糕的解决方案。需要编写更多代码,创建更多奇怪的类型,而您仍然需要到处进行转换。
  • @CarlNorum:如果您的目标类型不是char,则只需将指针转换为UB;有效的类型规则基本上使 C 成为一种强类型语言,其中类型信息绑定到内存位置本身;然而,类型系统非常不健全,因为编译器会很乐意尝试通过错误类型的表达式访问内存,但实际上可能会假设这些不变量具有更高的优化级别(例如在strict-aliasing 的情况下)
  • 您的示例中“未定义”行为的示例是什么?
  • @CarlNorum:通过联合的类型双关语是完美定义的(只要您读取的成员比您上次写入的成员短,并且您不创建陷阱表示); C99 中甚至有一个脚注告诉你;但是,它在附件中被错误地列为 UB,已用 C11 更正

标签: c pointers memory undefined-behavior


【解决方案1】:

转换为 char *(或 unsigned char * 或其类型定义)是一种特殊情况,不会导致未定义的行为。

来自 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。
  • 当然:C11 (PDF link)C99 (PDF link),任你选择。
  • 我是 C 新手,只是想知道 char *pf = (char *)&amp;float[i];。你到底在向char *投什么? (我的编译器为该行抱怨parse error before 'float' ..)
  • 哎呀,错字了。那应该是&amp;values[i]。修复。
  • @qwwqwwq:这是一个错字。将float 更改为values
猜你喜欢
  • 2011-08-29
  • 1970-01-01
  • 2013-08-05
  • 2011-12-13
  • 2021-08-13
  • 2011-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多