我读了这个on a blog:
违反类型规则:将int* 强制转换为float* 并解引用它(将“int”当作“float”访问)是未定义的行为。C要求通过memcpy进行以下类型转换:使用指针强制类型转换是不正确的,并且会导致未定义的行为。这方面的规则非常微妙,我不想在这里深入细节(char* 有一个例外,向量有特殊属性,联合会改变事情,等等)。这种行为启用了一种称为“基于类型的别名分析”(TBAA)的分析,编译器中的大量内存访问优化都使用这种分析。并且可以显著提高生成代码的性能。例如,此规则允许clang优化此函数:
如何使用memcpy函数进行类型强制?char* 的异常又如何呢?
我不明白如何使用memcpy函数进行类型强制?
1条答案
按热度按时间vh0rcniy1#
假设
float
的值为1.25,并希望确认其实际的IEEE-754十六进制表示形式为3fa00000
,则至少有四种不同的方法可以尝试执行此操作:(1)取一个
float
指针并将其强制转换为整型指针,并间接作用于它:(This片段默认为32位
int
。为了获得更好的可移植性,您可以使用printf("%08" PRIx32 "\n", *(uint32_t *)&f);
。)(2)使用活接头:
(3)使用
char
指针,并迭代/索引:(Note此代码片段采用小端字节序。)
(4)使用
memcpy
:现在,带回家的教训是,由于strict aliasing rule,* 并非所有这些方法都能可靠地工作 *。
特别是方法(1)是完全非法的,这是严格别名规则所不允许的教科书式的例子。
我 * 认为 * 你仍然可以像方法2那样使用联合,但是你可能必须戴上语言律师的帽子来说服自己。(也可以参见下面对这个答案的评论)
然而,方法(3)和(4)仍然有效,因为它们利用了严格别名规则的一个显式例外,也就是说,只要“错误类型”是一个字符指针,就允许你使用一个“错误”类型的双关指针来访问对象的位。
所以我想这是很清楚的,但是在回答你的具体问题时:
如何使用
memcpy
函数进行类型强制?如方法(4)。
那么
char *
的异常又如何呢?这是允许方法(3)工作的严格别名规则中的显式例外。
顺便说一句,C和C中的规则有很大的不同,严格地说,我相信在C中甚至连方法都没有(3)是法律的的,唯一允许你做这类事情的方法就是方法(4)和对
memcpy
的隐式调用。(然而,我听说优化编译器现在倾向于非常特别地处理对memcpy
的调用,不仅用内联寄存器移动替换显式函数调用,但有时甚至会完全优化副本,并在内部执行类似方法1或2的操作,如果他们知道可以成功的话。)