73

以下のプログラムを実行してみました。

#include <stdio.h>

int main() {
    signed char a = -5;
    unsigned char b = -5;
    int c = -5;
    unsigned int d = -5;

    if (a == b)
        printf("\r\n char is SAME!!!");
    else
        printf("\r\n char is DIFF!!!");

    if (c == d)
        printf("\r\n int is SAME!!!");
    else
        printf("\r\n int is DIFF!!!");

    return 0;
}

このプログラムでは、次の出力が得られます。

文字は違います!!! intは同じです!!!

両方で異なる出力が得られるのはなぜですか?
出力は次のようになりますか?

文字は同じです!!! intは同じです!!!

コードパッド リンク

4

5 に答える 5

36

クールな質問!

両方のintintにまったく同じビットが含まれているため、比較は機能します。したがって、それらは本質的に同じです。しかし、charsはどうですか?

ああ、Cはさまざまな場合charに s をints に暗黙的に昇格させます。これはそれらの1つです。あなたのコードは と言ってif(a==b)いますが、コンパイラが実際にそれを変換するのは次のとおりです。

if((int)a==(int)b) 

(int)a-5 ですが、(int)b251 です。それらはまったく同じではありません。

編集: @Carbonic-Acid が指摘したように、aが 8 ビット長(int)bの場合にのみ 251です。が 32 ビット長のchar場合、 -32764 です。int(int)b

再編集: バイトが 8 ビット長でない場合の答えの性質について議論しているコメントがたくさんあります。この場合の唯一の違いは、(int)b251 ではなく、-5 ではない別の正の数であることです。これは、まだ非常にクールな質問とはあまり関係ありません。

于 2013-06-26T06:02:44.617 に答える
21

整数プロモーションへようこそ。ウェブサイトから引用する場合:

int が元の型のすべての値を表すことができる場合、値は int に変換されます。それ以外の場合は、unsigned int に変換されます。これらは整数プロモーションと呼ばれます。他のすべての型は、整数の昇格によって変更されません。

C は、このような比較を行うと非常に混乱する可能性があります。私は最近、C 以外のプログラミングの友人の何人かを、次のいじめで困惑させました。

#include <stdio.h>
#include <string.h>

int main()
{
    char* string = "One looooooooooong string";

    printf("%d\n", strlen(string));

    if (strlen(string) < -1) printf("This cannot be happening :(");

    return 0;
}

これは実際にThis cannot be happening :(出力され、25 が -1 より小さいことを示しているようです!

ただし、下で発生するのは、-1 が符号なし整数として表されることです。これは、基になるビット表現により、32 ビット システムでは 4294967295 に等しくなります。当然、25 は 4294967295 より小さいです。

size_tただし、によって返される型strlenを符号付き整数として明示的にキャストすると、次のようになります。

if ((int)(strlen(string)) < -1)

次に、25 と -1 を比較すると、すべてがうまくいきます。

優れたコンパイラは、符号なし整数と符号付き整数の比較について警告するはずですが、それでも見落としがちです (特に警告を有効にしない場合)。

これは、すべてのプリミティブ型が署名されているため、Java プログラマーにとって特に混乱を招きます。James Gosling (Java の作成者の 1 人)は、この件に関して次のように述べています

Gosling: 言語設計者としての私にとって (最近はそうではありませんが)、「単純」が最終的に意味するものは、J. Random 開発者が仕様を頭の中に保持することを期待できるかということでした。その定義は、たとえばJavaはそうではないと言っています。実際、これらの言語の多くは、多くのコーナーケース、つまり誰も本当に理解していないものになります。符号なしについて C 開発者に質問すると、すぐに、符号なしで何が行われるか、符号なし演算とは何かを実際に理解している C 開発者はほとんどいないことがわかります。そのようなことが C を複雑にしました。Java の言語部分はかなり単純だと思います。検索する必要があるライブラリ。

于 2013-06-26T06:13:09.793 に答える
1

私の要点は、コンパイル時に「符号付きと符号なしの式を比較しています」という警告が表示されませんでしたか?

コンパイラは、彼がクレイジーなことをする資格があることをあなたに知らせようとしています! :) 私は追加します、プリミティブ型の容量に近い大きな値を使用すると、クレイジーなことが起こります。と

 unsigned int d = -5;

間違いなく d に大きな値を割り当てている場合、次のように同等です (同等であることが保証されていない場合でも):

 unsigned int d = UINT_MAX -4; ///Since -1 is UINT_MAX

編集:

ただし、興味深いことに、2 番目の比較だけが警告を発します(コードを確認してください)。したがって、変換規則を適用するコンパイラは、 と の比較でエラーが発生しないことを確信していることを意味しますunsigned char(char比較中に、可能なすべての値を安全に表現できる型に変換されます)。そして、彼はこの点で正しいです。unsigned int次に、これはandの場合には当てはまらないことを通知しますint: 比較中に、2 つのうちの 1 つが完全には表現できない型に変換されます。

完全を期すために、短いものでもチェックしました。コンパイラは文字の場合と同じように動作し、予想どおり、実行時にエラーはありません。

.

このトピックに関連して、最近この質問をしました(ただし、C++ 指向です)。

于 2013-06-26T06:35:14.017 に答える