6

このQ&Aに続いて、答えを調べようとしたので、次のように書きました。

#include <stdio.h>

int main ()
{

        int t;int i;
        for (i=120;i<140;i++){
                t = (i - 128) >> 31;
                printf ("t = %X , i-128 = %X ,  ~t & i = %X , ~t = %X \n", t, i-128 , (~t &i), ~t);
        }

        return 0;
}

出力は次のとおりです。

t = FFFFFFFF , i-128 = FFFFFFF8 ,  ~t & i = 0 , ~t = 0 
t = FFFFFFFF , i-128 = FFFFFFF9 ,  ~t & i = 0 , ~t = 0 
t = FFFFFFFF , i-128 = FFFFFFFA ,  ~t & i = 0 , ~t = 0 
t = FFFFFFFF , i-128 = FFFFFFFB ,  ~t & i = 0 , ~t = 0 
t = FFFFFFFF , i-128 = FFFFFFFC ,  ~t & i = 0 , ~t = 0 
t = FFFFFFFF , i-128 = FFFFFFFD ,  ~t & i = 0 , ~t = 0 
t = FFFFFFFF , i-128 = FFFFFFFE ,  ~t & i = 0 , ~t = 0 
t = FFFFFFFF , i-128 = FFFFFFFF ,  ~t & i = 0 , ~t = 0 
t = 0 , i-128 = 0 ,  ~t & i = 80 , ~t = FFFFFFFF 
t = 0 , i-128 = 1 ,  ~t & i = 81 , ~t = FFFFFFFF 
t = 0 , i-128 = 2 ,  ~t & i = 82 , ~t = FFFFFFFF 
t = 0 , i-128 = 3 ,  ~t & i = 83 , ~t = FFFFFFFF 
t = 0 , i-128 = 4 ,  ~t & i = 84 , ~t = FFFFFFFF 
t = 0 , i-128 = 5 ,  ~t & i = 85 , ~t = FFFFFFFF 
t = 0 , i-128 = 6 ,  ~t & i = 86 , ~t = FFFFFFFF 
t = 0 , i-128 = 7 ,  ~t & i = 87 , ~t = FFFFFFFF 
t = 0 , i-128 = 8 ,  ~t & i = 88 , ~t = FFFFFFFF 
t = 0 , i-128 = 9 ,  ~t & i = 89 , ~t = FFFFFFFF 
t = 0 , i-128 = A ,  ~t & i = 8A , ~t = FFFFFFFF 
t = 0 , i-128 = B ,  ~t & i = 8B , ~t = FFFFFFFF 

~t負の数が整数として宣言されているのは-1 == 0xFFFFFFFFなぜtですか?

4

5 に答える 5

5

t = (i - 128) >> 31 が各数値に対して 0 または -1 を与えるのはなぜですか?

非負の 32 ビット整数が右に 31 桁シフトされると、ゼロ以外のすべてのビットがシフトアウトされ、最上位ビットが 0 で埋められるため、最終的には 0 になります。

通常、負の 32 ビット整数が右に 31 桁シフトされると、最上位ビットは 0 で埋められず、代わりに数値の符号に設定されるため、符号はすべてのビットと 2 の補数表現に伝播します。 1 に設定されたすべてのビットは -1 になります。正味の効果は、数値を 2 で繰り返し割ったかのようですが、少しひねりがあります... 結果は、0 ではなく -infinity に丸められます。たとえば-2>>1==-1、 but -3>>1==-2and -5>>1==-3. これは算術右シフトと呼ばれます。

「通常」と言うとき、C 標準では、負の値の右シフトに対していくつかの異なる動作が許可されているという事実を意味します。その上、符号付き整数の非 2 の補数表現を許可します。ただし、通常、2 の補数表現と、上で示した/説明した動作があります。

于 2013-03-31T13:48:18.757 に答える
2

0 または-1tのいずれかであるため、~t も常に -1 または 0 です。

これは、(実装で定義された) or の動作によるもので(i - 128) >> 31、基本的に (i-128) [32 ビット整数を想定] の最上位ビットをコピーします。> 128 の場合i、最上位ビットがゼロになります。iが 128 未満の場合、結果は負であるため、最上位ビットが設定されます。

~tは「」の反対のすべてのビットであるため、がゼロの場合は常に 0xfffffffftであると期待できます。tt

于 2013-03-31T13:29:06.427 に答える
1

演算子である右シフトは>>、ほとんどのコンパイラで算術右シフトであり、2 による除算を意味します。

したがって、たとえばint i ==-4(0xfffffffc) の場合、 i>>1 == -2(0xfffffffe) となります。

そうは言っても、コードのアセンブリを確認することをお勧めします。
たとえば、x86 には 2 つの別個の命令 ( shr& sar) があり、それぞれ論理シフトと算術シフトを示します。
一般に、コンパイラは符号なし変数にはshr(論理シフト) を使用し、符号付き変数sarには (算術シフト) を使用します。


以下は、で生成された C コードと対応するアセンブリgcc -Sです。

交流:

int x=10;
unsigned int y=10;

int main(){
    unsigned int z=(x>>1)+(y>>1);
    return 0;
}

なので:

    .file   "a.c"
.globl x
    .data
    .align 4
    .type   x, @object
    .size   x, 4
x:
    .long   10
.globl y
    .align 4
    .type   y, @object
    .size   y, 4
y:
    .long   10
    .text
.globl main
    .type   main, @function
main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $16, %esp
    movl    x, %eax
    sarl    %eax ; <~~~~~~~~~~~~~~~~ Arithmetic shift, for signed int
    movl    y, %edx
    shrl    %edx ; <~~~~~~~~~~~~~~~~ Logical shift, for unsigned int
    addl    %edx, %eax
    movl    %eax, -4(%ebp)
    movl    $0, %eax
    leave
    ret
    .size   main, .-main
    .ident  "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
    .section    .note.GNU-stack,"",@progbits
于 2013-03-31T14:30:41.210 に答える
0

C および C++ の規則では、負の値の右シフトの結果は実装定義です。したがって、コンパイラのドキュメントを読んでください。あなたが得たさまざまな説明は有効なアプローチですが、言語定義によって義務付けられているものはありません。

于 2013-03-31T19:43:54.893 に答える