什么';用C重新解释内存的正确方法是什么?
很久以前,我已经记不清我在C中做过多少次这样的事情:什么';用C重新解释内存的正确方法是什么?,c,pointers,memory,undefined-behavior,C,Pointers,Memory,Undefined Behavior,很久以前,我已经记不清我在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
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;
}
我刚刚发现,通过强制转换到另一个指针类型来重新解释这样一段内存会调用未定义的行为。然而,上述所有例子的目的都是绝对必要的。正确的方法是什么?强制转换为
字符*
(或无符号字符*
或其类型定义)是一种特殊情况,不会导致未定义的行为
根据C规范,6.3.2.3指针,第7段:
当指向对象的指针转换为指向字符类型的指针时,结果将指向对象的最低寻址字节。结果的连续增量(直到对象的大小)产生指向对象剩余字节的指针
本案例涵盖了您的第一个和第三个示例。第二个例子有点可疑,但可能适用于大多数系统。您真正应该做的是直接读取值
:
float values[256];
receive(values, sizeof values); // assuming receive() takes a "void *" parameter
或类似的内容(以避免对齐问题):
char缓冲区[1024];
接收(缓冲区,缓冲区大小);
浮点值[256];
对于(int i=0;i<256;i++)
{
char*pf=(char*)和值[i];
memcpy(pf,buffer+i*sizeof(float),sizeof(float));
}
(注意,我将
buffer
更改为char
数组-我认为这是您问题中的一个输入错误)。您能提供一个链接吗?我的K&R C书没有说那么多。。。但这又不是ISO或ANSI C。当然,或者,你的选择。我是C新手,只是想知道char*pf=(char*)&float[I]代码>。在这里,你到底在向char*
投射什么?(我的编译器抱怨那一行在“float”之前出现了解析错误。
。)哎呀,输入错误。这应该是&值[i]
。正在修复。@qwwqwwq:这是一个打字错误。将float
更改为values
。我可以让您对union
关键字感兴趣吗?就个人而言,我认为使用union解决这些问题比使用typecast更糟糕。要编写更多的代码,创建更多奇怪的类型,你仍然需要到处施放。@CarlNorum:如果你的目标类型不是char
,只要施放指针就可以找到UB;有效的类型规则基本上使C成为一种强类型语言,其中类型信息绑定到内存位置本身;然而,类型系统是非常不健全的,因为编译器会很高兴地尝试通过错误类型的表达式访问内存,但实际上可能会假设这些不变量具有更高的优化级别(例如在严格别名的情况下)
)什么是“未定义”的示例您的示例中的行为?@CarlNorum:通过联合的类型双关是非常明确的(只要您从中读取的成员比您上次写入的成员短,并且您不创建陷阱表示);C99中甚至有一个脚注告诉你这一点;但是,附件中错误地将其列为UB,并用C11进行了更正
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));
}