13

すべての値が1バイト以上であり、どのバイトにもメタデータを含めることができない場合、システムはどのようにして1バイトが表す数値の種類を追跡しますか?ウィキペディアで2の補数とシングルポイントを調べると、これらの数値を基数2で表す方法がわかりますが、コンパイラまたはプロセッサ(ここで実際に扱っているのは不明)がこのバイトをどのように決定するのか疑問に思っています符号付き整数である。

これは、暗号化された手紙を受け取り、私の暗号の棚を見て、どれをつかむべきか疑問に思うことに似ています。何らかの指標が必要です。

この問題を解決するために私が何をすべきかを考えると、2つの解決策が思い浮かびます。追加のバイトを要求してそれを使用して説明を格納するか、メモリのセクションを数値表現専用に割り当てます。符号付き数値のセクション、フロートのセクションなど。

私は主にUnixシステムでCを扱っていますが、これはもっと一般的な質問かもしれません。

4

5 に答える 5

9

システムは、バイトが表す数値の種類をどのように追跡しますか?

「システム」はそうではありません。変換中、コンパイラは処理しているオブジェクトのタイプを認識し、それらの値を処理するための適切なマシン命令を生成します。

于 2013-03-01T17:42:26.210 に答える
1

ああ、いい質問だ。CPUから始めましょう-Intelx86チップを想定しています。

CPUは、バイトが「符号付き」か「符号なし」かを認識していないことがわかります。したがって、2つの数値を加算するか、または任意の操作を実行すると、「ステータスレジスタ」フラグが設定されます。

「サインフラグ」を見てください。2つの数値を加算すると、CPUはまさにそれを実行します-数値を加算し、結果をレジスタに格納します。しかし、CPUは、「代わりに、これらの数値を2の補数の符号付き整数として解釈した場合、結果は負になりますか?」と言います。その場合、その「サインフラグ」は1に設定されます。

したがって、プログラムが署名付きと署名なしのアセンブリ書き込みを気にする場合は、そのフラグのステータスを確認し、プログラムの残りの部分がそのフラグに基づいて別のタスクを実行します。

したがって、Cでsigned intvsを使用する場合、基本的には、その符号フラグを使用する方法(または使用するかどうか)をコンパイラーに指示します。unsigned int

于 2013-03-01T17:28:01.080 に答える
1

CとC++は高級言語であることを覚えておくことが重要です。コンパイラの仕事は、コードのプレーンテキスト表現を取得し、ターゲットプラットフォームが実行することを期待しているプラ​​ットフォーム固有の命令にコードを組み込むことです。PCを使用しているほとんどの人にとって、これはx86アセンブリである傾向があります。

これが、CとC++が基本的なデータ型を定義する方法に非常に緩い理由です。たとえば、ほとんどの人は1バイトに8ビットがあると言います。これは標準で定義されておらず、データのネイティブな解釈として1バイトあたり7ビットを使用しているマシンに反対するものはありません。この規格は、バイトがアドレス可能なデータの最小単位であることのみを認識します。

したがって、データの解釈はプロセッサの命令セット次第です。多くの現代言語では、これに加えて別の抽象化である仮想マシンがあります。

独自のスクリプト言語を作成する場合は、ソフトウェアでデータをどのように解釈するかを定義するのはあなた次第です。

于 2013-03-01T17:37:18.163 に答える
1

実行されるコードには、タイプに関する情報はありません。タイプを知っている唯一のツールは、コードをコンパイルするときのコンパイラーです。Cの型は、どこかで間違った型を使用することを防ぐためのコンパイル時の制限にすぎません。コンパイル中、Cコンパイラは各変数の型を追跡するため、どの型がどの変数に属しているかを認識します。

printfこれが、たとえば、でフォーマット文字列を使用する必要がある理由です。printfこの情報が失われるため、パラメータリストにどのタイプが含まれるかを知る機会はありません。goやjavaのような言語では、型を取得できるリフレクション機能を備えたランタイムがあります。

コンパイルされたCコードにまだ型情報が含まれているとすると、結果のアセンブラー言語で型をチェックする必要があります。アセンブリ内の型に近いのは、接尾辞(GAS内)によって決定される命令のオペランドのサイズだけであることがわかります。したがって、タイプ情報から残っているのはサイズであり、それ以上のものではありません。

タイプをサポートするアセンブリの1つの例は、プリミティブのオペランドのタイプサフィックスを持つJavaVMバイトコードです。

于 2013-03-01T17:39:40.873 に答える
0

コンパイラのほかにCを使用すると、指定された値のタイプを完全に把握しているため、指定された値のタイプを認識しているシステムはありません。

C自体は、実行時型情報システムを備えていないことに注意してください。

次の例を見てください。

int i_var;
double d_var;

int main () {

  i_var = -23;
  d_var = 0.1;

  return 0;
}

コードには、整数として格納される値と倍精度値として格納される値の2種類の値が含まれています。

コードを分析するコンパイラは、両方の正確なタイプをよく知っています。ここで、生成コードがgccに渡されることによって生成される間に保持される型情報gccの短いフラグメントのダンプ-fdump-tree-all

@1      type_decl        name: @2       type: @3       srcp: <built-in>:0      
                         chan: @4      
@2      identifier_node  strg: int      lngt: 3       
@3      integer_type     name: @1       size: @5       algn: 32      
                         prec: 32       sign: signed   min : @6      
                         max : @7      
...
@5      integer_cst      type: @11      low : 32      
@6      integer_cst      type: @3       high: -1       low : -2147483648 
@7      integer_cst      type: @3       low : 2147483647 
...

@3805   var_decl         name: @3810    type: @3       srcp: main.c:3      
                         chan: @3811    size: @5       algn: 32      
                         used: 1       
...
@3810   identifier_node  strg: i_var    lngt: 5    

@linksを探すと、ノード@1-3および@に格納されているタイプ"int"のメモリサイズ、配置制約、および許可されている最小値と最大値について、実際に多くの情報が格納されていることがはっきりとわかります。 5-7。(前述の「 chan 」エントリは、生成されたツリー内のタイプ定義を追跡するために使用されるため、@ 4ノードを省略しました

main.cの3行目で宣言されている変数については、ノード@3への型参照からわかるようにint型の値を保持していることがわかります。

自分でd_varのダブルエントリとd_varのエントリを自分で探し出すことができるはずです。信頼できない場合は、それらもそこにあります。

リストされている(gcc pass the -Sswitchを使用して)生成されたアセンブラーコードを見ると、コンパイラーがコード生成でこの情報をどのように使用したかを見ることができます。

    .file   "main.c"
    .comm   i_var,4,4
    .comm   d_var,8,8
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    movl    $-23, i_var
    fldl    .LC0
    fstpl   d_var
    movl    $0, %eax
    popl    %ebp
    ret
    .size   main, .-main
    .section    .rodata
    .align 8
.LC0:
    .long   -1717986918
    .long   1069128089
    .ident  "GCC: (Debian 4.4.5-8) 4.4.5"
    .section    .note.GNU-stack,"",@progbits

割り当て命令を見ると、コンパイラがint値を割り当てるための正しい命令「mov」と「double」値を割り当てるための「fstp」を理解していることがわかります。

それにもかかわらず、マシンレベルで選択された指示以外に、それらの値のタイプの表示はありません。.LC0に格納されている値を見ると、値0.1のタイプ「double」は、アセンブラの既知の「タイプ」を満たすために、2つの連続する格納場所でそれぞれ長い間分解されていました。

実際のところ、この方法で値を分割することは、他の可能性の1つの選択肢にすぎず、「type」.byteの8つの連続した値を使用することも同様にうまくいきます。

于 2013-03-01T18:21:58.837 に答える