2017-02-11 6 views
3

に異なっている私はこのようなコード・スニペット(up.cpp)を有する:64ビット整数へのポインタを変換する、なぜ結果は32ビット・64ビットプラットフォーム

#include <stdio.h> 

typedef unsigned long long Uint64; 
int main() 
{ 
    void *p = (void*)0xC00; 
    Uint64 u64 = (Uint64)p; 
    printf("{%llx}\n", u64); 

    return 0; 
} 

32とそれをコンパイルビットのgcc 4.8.1、私は出力を得る:

64ビットGCC 4.8.1とそれをコンパイル
{ffffffffc00} 

、私は出力を得る:

{c00} 

はい、64ビットの1は、3を与えます2ビット値。 gcc 4.8.1はopenSUSE 13.1のものです。

私は、Visual C++ 2010のx86 &のx64コンパイラ(ビットコードの変更、__int64%I64x)でそれを試みたが、驚くべきは、同じ結果を得ます。

もちろん、私はを両方のx86 & x64で入手しようと考えています。しかし、なぜそのような違いがありますか?

+0

"ll"を使用し、 "llu"を使用していないためです。 –

+0

@barakmanos:彼は '%llx'を使用しています。ここで' x'は符号なしと16進を意味します。 –

+0

しかし、最終的に出力フレーバーを制御したいのですが、 "%llx"は私に 'abcdef'を与え、 ''%llX "'は 'ABCDEF 'を与えます。 –

答えて

5

この

Uint64 u64 = (Uint64)p; 

の行動は、言語によって定義されていません。これは実装定義です。

32ビットプラットフォームでは、32ビットのポインタ値をどのように拡張するかについて、64ビットプラットフォームでは純粋に概念的な変換(ターゲット値全体を「塗りつぶす」) 64ビットの整数値に符号拡張または無しで?どうやら、あなたの実装はその値を署名拡張することに決めました。

あなたの実装では、符号なし変換へのポインタでは、元のポインタの値はという符号付きという値のソートとして動作するはずです。しかし、これはむしろ奇妙な決定だろう。私はGCCでそれを再現することはできません:http://coliru.stacked-crooked.com/a/9089ccda625bd65d

それはあなたのプラットフォーム上で何が起こるか本当にだ場合、あなたはuintptr_t(中間タイプとして)最初に変換することによって、この動作を抑制することができるはず、コメントで@barakマノスによって示唆されているように。

+0

おそらく 'uintptr_t'はこのプラットフォーム依存性を解決しますが(C言語標準がそれを定義しているかどうかはわかりませんが) –

+0

もちろん、符号なしの拡張を行う必要があります。ポインタが負であると想像するのはとても変です。 –

+0

@ JimmChen:AMD64メモリモデルは、下半分(ユーザー空間、0000から始まるアドレス)と上半分(カーネル空間、FFFFで始まるアドレス)に分かれています。符号付き整数として見ると、それぞれ正と負です。 – dan04

関連する問題