1

数か月前、私は 64 ビット Windows を搭載した CPU intel i7-2630qm を搭載したラップトップを手に入れました。このシステムでプログラミング スキルを練習しているときに、整数サイズに関していくつかの違いに遭遇しました。これは、おそらく新しい 64 ビット システムによるものだと思います。

コードを見てみましょう。

Cコード:

#include <stdio.h>

int main(void)
{
    int num = 20;

    printf("%d %lld\n" , num , num);

    return 0;
}

質問 :

201.) この新しいラップトップを入手する前のことを覚えています。つまり、古い 32 ビット システムをまだ使用しているということです%lld。 .

2.)しかし、この現象は、新しいラップトップを使用しているときに発生しなくなりました。代わりに、変数numを type に変更しても、両方の整数が正しく出力されshortます。

3.)それは 64 ビット システム上にありint、引数として使用すると long long に昇格する新しい整数昇格がありますか??または、引数として渡すと 64 ビットにもshort昇格できる整数ですか? long long?

int4.)それに加えて、16ビットシステムでは16ビットであり、32ビットシステムでは32ビットになるという1つのことでかなり混乱しています.しかし、なぜ64にならないのですか? 64ビットの場合はビット??

================================================== ================================ アドオン:

1.)新しいラップトップを使用している間、IDE のプロジェクトとして「コンソール プログラム (64 ビット)」を選択しましたが、32 ビットの古い PC システムでは「コンソール プログラム」を選択しました。

2.)演算子をint使用して「コンソール プログラム (64 ビット)」プロジェクトのサイズを確認したところ、 16ビットのままsizeofで 32 ビットが返されます。通常の 64 ビット サイズ。shortlonglong long

4

4 に答える 4

3

x64コードでは呼び出し規約が異なるため、この副作用が発生しています。32ビットx86コードの関数の引数はスタックに渡されます。printf()関数は、アクティベーションフレームの一部ではないスタックから単語を読み取ります。値が0である確率は非常に低いです。

x64コードでは、関数の最初の4つの引数は、スタックではなくCPUレジスタを介して渡されます。64ビットレジスタの上位ワードが偶然にゼロになる確率はかなり高いです。少数で機能していた以前の64ビット操作によってそこに残されました。しかし、確かに保証されていません。

未定義の振る舞いの定義された振る舞いを推論しようとすることは、そうでなければ役に立ちません。マシンにあるコアに言語がどのように実装されているかを推測しようとする以外に。そのためのより良いリソースがあります。コンパイラに適用できるマシンコードを学ぶことは、優れたショートカットです。Cコードがどのようにマシンコードに変換されたかを示すまともなデバッガーと一緒に。マシンコードには未定義の動作はありません。

于 2011-09-18T20:01:01.810 に答える
1

現在、Windows 64 ビット コンパイラにアクセスすることはできませんが、私の推測では次のようになります。

あなたの質問は整数の昇格に関するものではなく、関数の呼び出し元から呼び出された関数にパラメーターがどのように渡されるかに関するものです。これは C 仕様を超えていますが、知っておくと興味深いことです。

32 ビットでは、すべてのレジスタが 32 ビットを保持できるため、すべてのパラメータが 32 ビット ブロックに分割されます。したがって、この場合、次のスタック レイアウトがあります。

[ 32-bit format string pointer ][ num as 32-bit ][ num as 32-bit ] junk...

64 ビットでは、すべてのレジスタが 64 ビットを保持できるため、すべてのパラメータが 64 ビット ブロックに分割されます。したがって、スタックには次のものが含まれます。

[ 64-bit format string pointer ][ num as 64-bit ][ num as 64-bit ] junk...

32 ビット値を保持する 64 ビット レジスタの上位 32 ビットは、便宜的にゼロに設定されます。

そのため、 が 64 ビット数を読み取る場合printf、32 ビット プラットフォームでは 2 つの 32 ビット レジスタに相当するものをロードしますが、64 ビット プラットフォームでは上位ビットがクリアされた 1 つの 64 ビット レジスタのみをロードします。

于 2011-09-18T19:36:38.003 に答える
1

(1 および 2) 既に述べたように、この状況での動作は定義されていないため、コンパイラは何らかの理由で異なる動作をすることが許可されています。

(3) コンパイラは int を 64 ビットとして定義できます。この場合、問題のすべての変数が同じサイズになるため、昇格は必要ありません。しかし、ほぼ確実にそうではありません。

(4) ほとんどまたはすべての 64 ビット コンパイラでは、int は 32 ビットです。これは、長い間 int が 32 ビットであり、プログラマーがそれを期待するようになり、それを変更すると既存のコードが壊れてしまうためです。私の知る限り、これは正式な標準の一部ではありませんが、変更がさらに困難な事実上の標準の 1 つです。:-)

于 2011-09-18T19:43:52.383 に答える
1

記述しているものはすべて、コンパイラが使用している仕様と使用しているプラ​​ットフォームに固有のものです (ただし、longと少なくとも同じサイズであることが保証されていますint):

ウィキペディアのエントリ:

ロングロング

整数

c99 標準は、特定の型を追加することによって、このあいまいさを終わらせようとしています。int32_tuint64_tなど。 などを定義する POSIX 仕様もありますu_int32_t

編集:についての質問を見逃しましたprintf()。申し訳ありません。@nos が質問のコメントで指摘しているように、 a 以外のものをlong longtoに渡すと%lld未定義の動作が発生します。これは、それが何をするかについて韻や理由がないことを意味します。ユニコーンが自発的に出現することは問題外ではありません。

ああ、私が知っているすべてのコンパイラと OSintは 32 ビットです。これを変更すると、32 ビットであることに依存するものが壊れる可能性があります。

于 2011-09-18T19:14:09.653 に答える