0

我正在尝试这个指针技巧,但我不知道如何修复它,我在 ubuntu 12.04 64 位上运行 g++ 4.6。查看下面的代码:

int arr[5];
arr[3] = 50;
((short*) arr)[6] = 2;
cout << arr[3] << endl;

逻辑是:因为short是 2 个字节,int是 4 个字节,我想更改 中的前 2 个字节arr[3],同时将后 2 个字节的值保持为 50。所以我只是在弄乱位模式。不幸的是,sizeof(int*)sizeof(short*)都是8个字节。是否有返回大小为 2 字节的指针的类型转换?

更新:

我意识到这个问题写得不好,所以我会解决这个问题:cout << arr[3] << endl;我得到的输出是2。我想要得到的输出既不是2也不是50,而是一个很大的数字,表明左边的部分int 位模式的值已更改,而存储在 arr[3] 中的 int 的右侧部分(第二个 2 位)仍保持不变。

4

6 回答 6

5

sizeof(int*)并且sizeof(short*)两者都将是相同的——正如将sizeof(void*)——你要求的是指针的大小,而不是指针指向的东西的大小。

使用sizeof(int)sizeof(short)代替。


现在,对于您的代码片段,您正在对正在运行的机器的字节序进行假设。给定平台上的“第一”部分int可能是地址较高的字节,也可能是地址较低的字节。

例如,您的内存块可能是这样布置的。假设最低有效字节的索引为零,而最高有效字节的索引为一。在大端架构上,int 可能如下所示:

 <------------- 4 bytes --------------->
+---------+---------+---------+---------+
| int:3   | int:2   | int:1   | int:0   |
| short:1 | short:0 | short:1 | short:0 |
+---------+---------+---------+---------+

请注意 int 中的第一个 short (在您的情况下应该是((short*) arr)[6])如何包含 int 的最高有效位,而不是最低有效位。因此,如果您覆盖((short*) arr)[6],您将覆盖 的最高有效位arr[3],这似乎是您想要的。但是 x64 不是大端机器。

在小端架构上,您会看到:

 <------------- 4 bytes --------------->
+---------+---------+---------+---------+
| int:0   | int:1   | int:2   | int:3   |
| short:0 | short:1 | short:0 | short:1 |
+---------+---------+---------+---------+

导致相反的行为 -((short*) arr)[6]将是 的最低有效位arr[3],并且((short*) arr)[7]将是最重要的。


这是我的机器发生的事情——你的机器可能不同:

C:\Users\Billy\Desktop>type example.cpp
#include <iostream>

int main()
{
        std::cout << "Size of int is " << sizeof(int) << " and size of short is "
                  << sizeof(short) << std::endl;

        int arr[5];
        arr[3] = 50;
        ((short*) arr)[6] = 2;
        std::cout << arr[3] << std::endl;
        ((short*) arr)[7] = 2;
        std::cout << arr[3] << std::endl;
}


C:\Users\Billy\Desktop>cl /W4 /EHsc /nologo example.cpp && example.exe
example.cpp
Size of int is 4 and size of short is 2
2
131074
于 2013-02-27T06:20:32.657 回答
5

你的问题是由于endianness。Intel CPU 是 little endian,这意味着 int 的第一个字节存储在第一个地址中。让我举个例子:

假设 arr[3] 位于地址 10:

然后arr[3] = 50;将以下内容写入内存

10:   0x32
11:   0x00
12:   0x00
13:   0x00

并将((short*) arr)[6] = 2;以下内容写入内存

10:  0x02
11:  0x00
于 2013-02-27T06:34:50.107 回答
0

当您索引一个指针时,它会将索引乘以所指向类型的大小。因此,您不需要 2 字节指针。

于 2013-02-27T06:20:49.553 回答
0

你做了很多可能站不住脚的假设。另外,指针的大小与手头的问题有什么关系?

为什么不只使用位掩码:

arr[3] |= (top_2_bytes << 16);

这应该设置高 16 个字节而不干扰低 16 个字节。(您可能会进入有符号/无符号的戏剧)

于 2013-02-27T06:21:53.500 回答
0

综上所述,标准禁止这样做:通过指向另一种类型的指针设置变量是调用未定义的行为如果您知道您的机器是如何工作的(and 的大小intshort字节顺序,...)并且 您知道您的编译器(可能)如何翻译您的代码,那么您可能会侥幸成功。适用于整洁的客厅技巧,以及当机器/编译器/月相变化时的壮观爆炸。

如果它赢得任何性能,胜利将是最小的,甚至可能是净损失(很久以前我摆弄过的一个编译器,玩“我可以比编译器更好地实现这个循环,我确切地知道这里发生了什么”为我生成的代码比直接编写为循环的完全相同的代码要糟糕得多:我的“智能”代码使编译器感到困惑,它的“循环模式”不适用`label: ... if() goto label;

于 2013-02-27T17:52:35.143 回答
-1

您不希望您的实际指针大小为两个字节;这意味着它只能访问约 16k 的内存地址。但是,像您一样使用强制转换为短 *,将允许您每两个字节访问一次内存(因为编译器会将数组视为短数组,而不是整数数组)。

于 2013-02-27T06:23:08.637 回答