0

このポインタートリックを試していますが、修正方法がわかりません.ubuntu 12.04 64ビットでg ++ 4.6を実行しています。以下のコードを確認してください。

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

ロジックは次のとおりです:shortは 2 バイトなので、は 4 バイトです。2 番目の 2 バイトの値を 50 のままにして、int最初の 2 バイトを変更したいのです。arr[3]残念ながら、sizeof(int*)sizeof(short*)はどちらも 8 バイトです。サイズが 2 バイトのポインターを返す型キャストはありますか?

アップデート:

質問の書き方が悪いことに気付いたので、修正します: The output from cout << arr[3] << endl;I'm gets 2. 取得したい出力は 2 でも 50 でもなく、左側の部分がint ビット パターンの一部が変更されていますが、arr[3] に格納されている int の右側の部分 (2 番目の 2 ビット) は変更されていません。

4

6 に答える 6

5

Your problem is due to endianness. Intel CPU's are little endian meaning that the first byte of an int is stored in the the first address. Let me how you can example:

Let's assume that arr[3] is at address 10:

Then arr[3] = 50; Writes the following to memory

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

And ((short*) arr)[6] = 2; writes the following to memory

10:  0x02
11:  0x00
于 2013-02-27T06:34:50.107 に答える
5

sizeof(int*)両方ともsizeof(short*)同じになりますsizeof(void*)-そうであるように-ポインターが指すもののサイズではなく、ポインターのサイズを求めています。

代わりにsizeof(int)またはを使用してください。sizeof(short)


さて、コード スニペットに関しては、実行しているマシンのエンディアンについて仮定しています。特定のプラットフォームの の「最初の」部分は、int上位アドレスのバイト、または下位アドレスのバイトである場合があります。

たとえば、メモリ ブロックは次のように配置されている場合があります。最下位バイトのインデックスが 0 で、最上位バイトのインデックスが 1 だとします。ビッグ エンディアン アーキテクチャでは、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 に答える
0

上記のすべてのことを言いますが、標準ではそのようなことを禁止しています。別の型へのポインターを介して変数を設定すると、未定義の動作が呼び出されます。マシンがどのように機能するか ( と のサイズ、エンディアンなど) 知っていて、コンパイラがコードをどのように変換するか (可能性が高い) を知っている場合はそれでうまくいくかもしれません。月のマシン/コンパイラ/フェーズが変化したときの巧妙なパーラートリックと壮大な爆発に役立ちます.intshort

それが何らかのパフォーマンスを獲得したとしても、その勝利は最小限であり、純損失でさえある可能性があります (あるコンパイラーをいじって、「このループをコンパイラーよりもうまく実装できる。ここで何が起こっているかを正確に知っている」と遊んでいました)。ループとしてネイティブに記述されたまったく同じコードよりもはるかに悪いコードを生成しまし`label: ... if() goto label;た: 私の「スマートな」コードはコンパイラを混乱させ、その「ループのパターン」は適用されませんでした)。

于 2013-02-27T17:52:35.143 に答える
0

ポインターにインデックスを付けると、インデックスにポイント先の型のサイズを掛けた値が追加されます。したがって、2 バイトのポインターは必要ありません。

于 2013-02-27T06:20:49.553 に答える
0

あなたは、水を保持しないかもしれない多くの仮定をしています。また、 sizeof ポインターは、目前の問題とどのような関係がありますか?

ビットマスクを使用しない理由:

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

これにより、下位 16 バイトを乱すことなく上位 1​​6 バイトが設定されるはずです (署名付き/未署名のドラマに入る可能性があります)。

于 2013-02-27T06:21:53.500 に答える
-1

実際のポインターのサイズを 2 バイトにしたくないでしょう。これは、最大 16k のメモリ アドレスしかアクセスできないことを意味します。ただし、ショート * へのキャストをそのまま使用すると、2 バイトごとにメモリにアクセスできます (コンパイラは配列を int ではなく short の配列と見なすため)。

于 2013-02-27T06:23:08.637 に答える