Jac*_*iba 21 c++ gcc endianness compiler-flags language-lawyer
为什么这个程序的输出是4?
#include <iostream>
int main()
{
short A[] = {1, 2, 3, 4, 5, 6};
std::cout << *(short*)((char*)A + 7) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,在x86 little endian系统上,char有1个字节,短2个字节,输出应该是0x0500,因为数组中的数据A是十六进制的休闲:
01 00 02 00 03 00 04 00 05 00 06 00
Run Code Online (Sandbox Code Playgroud)
我们从开始向前移动7个字节,然后读取2个字节.我错过了什么?
Lig*_*ica 22
您在此违反了严格的别名规则.你不能只读到一个对象的中途,并假装它是一个独立的对象.你不能使用像这样的字节偏移来发明假想的对象.海湾合作委员会完全有权做疯狂的事情,比如回到过去并谋杀埃尔维斯普雷斯利,当你交出你的计划时.
你什么都允许做的是检查和处理,使一个任意的对象,使用的字节数char*.使用该权限:
#include <iostream>
#include <algorithm>
int main()
{
short A[] = {1, 2, 3, 4, 5, 6};
short B;
std::copy(
(char*)A + 7,
(char*)A + 7 + sizeof(short),
(char*)&B
);
std::cout << std::showbase << std::hex << B << std::endl;
}
// Output: 0x500
Run Code Online (Sandbox Code Playgroud)
但是你不能仅仅"弥补"原始集合中不存在的对象.
此外,即使您有一个可以被告知忽略此问题的编译器(例如,使用GCC的-fno-strict-aliasing开关),但是对于任何当前的主流架构,组合对象都没有正确对齐.A short不能合法地居住在内存†的奇数位置,所以你不能假装那里有一个.没有办法解决原始代码行为的未定义问题; 事实上,如果你通过GCC -fsanitize=undefined切换它会告诉你多少.
†我正在简化一点.
Jon*_*ely 12
由于将指针错误地对齐,程序具有未定义的行为(short*).这打破了C11中6.3.2.3 p6中的规则,这与其他答案中声明的严格别名无关:
指向对象类型的指针可以转换为指向不同对象类型的指针.如果生成的指针未针对引用的类型正确对齐,则行为未定义.
在[expr.static.cast] p13中,C++表示将未对齐转换char*为short*给出一个未指定的指针值,该值可能是无效指针,无法解除引用.
检查字节的正确方法是通过char*回送short*并假装存在short一个short无法生存的地址.
| 归档时间: |
|
| 查看次数: |
1180 次 |
| 最近记录: |