来自C ++数组上指针数学的未定义行为 [英] Undefined behavior from pointer math on a C++ array

查看:163
本文介绍了来自C ++数组上指针数学的未定义行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么这个程序的输出是 4

 #包括< iostream> 

int main()
{
short A [] = {1,2,3,4,5,6};
std :: cout<< *(short *)((char *)A + 7)<<<的std :: ENDL;
返回0;





$ b根据我的理解,在x86小端系统中,char有1个字节,和短的2个字节,输出应该是 0x0500 ,因为数组 A 中的数据是十六进制的: / p>

  01 00 02 00 03 00 04 00 05 00 06 00 

我们从7个字节开始向前移动,然后读取2个字节。我错过了什么?

解决方案

您在这里违反了严格的别名规则。你不能只是半读一个对象,并假装它是一个独立的对象。您不能使用像这样的字节偏移量来发明假设的对象。海湾合作委员会完全有权利做出疯狂的事情,就像回到过去并且杀死埃尔维斯普雷斯利,当你把它交给你的程序时。



允许使用 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;


//输出:0x500



现场演示



但是你可以在原始集合中只是补充一个不存在的对象。另外,即使你有一个可以被告知忽略这个问题的编译器(例如,使用GCC的 -fno-strict-aliasing 开关),对于任何当前的主流体系结构,组合对象都没有正确对齐。一个 short 不能合法地居住在内存中的奇数位置,所以你不能假装在那里有一个。没有办法解决原始代码的行为如何未定义;事实上,如果你通过GCC -fsanitize = undefined 开关,它会告诉你很多。



我正在简化一点。


Why the output of this program is 4?

#include <iostream>

int main()
{
    short A[] = {1, 2, 3, 4, 5, 6};
    std::cout << *(short*)((char*)A + 7) << std::endl;
    return 0;
}

From my understanding, on x86 little endian system, where char has 1 byte, and short 2 bytes, the output should be 0x0500, because the data in array A is as fallow in hex:

01 00 02 00 03 00 04 00 05 00 06 00

We move from the beginning 7 bytes forward, and then read 2 bytes. What I'm missing?

解决方案

You are violating strict aliasing rules here. You can't just read half-way into an object and pretend it's an object all on its own. You can't invent hypothetical objects using byte offsets like this. GCC is perfectly within its rights to do crazy sh!t like going back in time and murdering Elvis Presley, when you hand it your program.

What you are allowed to do is inspect and manipulate the bytes that make up an arbitrary object, using a char*. Using that privilege:

#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

(live demo)

But you can't just "make up" a non-existent object in the original collection.

Furthermore, even if you have a compiler that can be told to ignore this problem (e.g. with GCC's -fno-strict-aliasing switch), the made-up object is not correctly aligned for any current mainstream architecture. A short cannot legally live at that odd-numbered location in memory, so you doubly can't pretend there is one there. There's just no way to get around how undefined the original code's behaviour is; in fact, if you pass GCC the -fsanitize=undefined switch it will tell you as much.

I'm simplifying a little.

这篇关于来自C ++数组上指针数学的未定义行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆