短いintのscanfの奇妙な振る舞い

コードは次のとおりです。

#include 
main()
{
    int m=123;
    int n = 1234;
    short int a;
    a=~0;
    if((a>>5)!=a){
        printf("Logical Shift\n");
        m=0;
    }
    else{
        printf("Arithmetic Shift\n");
        m=1;
    }
    scanf("%d",&a);
    printf("%d\n", m);
}

after the line scanf("%d",&a); the value of m becomes 0.

私はそれがscanfによって引き起こされる可能性があることを知っています:aの型は短く、入力の型はintです。しかし、これはどのようにしてmの価値に影響を及ぼしますか?

どうもありがとう !

2

5 答え

スニペット内の m である最も一般的な理由は、ifステートメントの本文にこの値を持つように m コードには未定義の動作が含まれているため、誰もそのことを確信できません。


The likely story about passing a short* when scanf expects an int*

sizeof(short)= 2 sizeof(int)== 4 と仮定します。

あなたのメイン関数を入力するとき、変数が存在するスタックは、通常以下のようになります:

  _
 |short int (a)   : scanf will try to read an int (4 bytes).
 |_ 2 bytes       : This part of memory will most
 |int       (n)   : likely be overwritten
 |                :..
 |
 |_ 4 bytes
 |int       (m)
 |
 |
 |_ 4 bytes

変数 m に影響を及ぼさない a 変数に%d (つまり int >のようになりますが、 n はその一部を上書きする可能性が高くなります。


未定義の動作

Though it's all a guessing game since you are invoking what we normally refer to as "未定義の動作" when using your scanf statement.

スタンダードが保証しないものはすべてUBです。その結果は何でもかまいません。おそらく、別の変数の一部である別のセグメントにデータを書き込むか、あるいは、宇宙を爆破させるかもしれません。

UBが存在する別の日を見るために私たちが生きることを誰も保証することはできません。


How to read a short int using scanf

%hd を使用し、 short * を渡すようにしてください。

7
追加された
+1、Lounge でこれを投稿する
追加された 著者 ApprenticeHacker,
このスレッドのほとんどの回答は完全に間違っているわけではありません。は誤解を招き、間違っています。ほとんどすべての回答に「未定義の動作」と書かれています。エフェクトはせいぜい可能性の高い推測の後であるため、あなたのオープニングステートメントが意味することを理解できません。
追加された 著者 Alok Save,
あなたはあなたの答えに何も言うことは自由ですが、古いタイトルは他の答えに正義をしませんでした。あなたの答えが同じではない場合、同じ答えが同じであると言います。
追加された 著者 Alok Save,
@IntermediateHackerあなたはこれを行うために私の小さな黒いお尻を+1する必要があります: シークレットのためのここをクリックし、私たちは持っていませんクッキー (これはSOのチャットルーム Lounge へのリンクです)
追加された 著者 Filip Roséen - refp,
@Als少し皮肉だった、私は疲れていて、疲れました。あなたが好きなら、あなたのタイトルを変えることができます。
追加された 著者 Filip Roséen - refp,
私たちは行く! ;-)
追加された 著者 Filip Roséen - refp,

Assuming that int and short are four- and two-byte integers, respectively, on your platform (which is a likely assumption, but not guaranteed by the standard), you're asking scanf to read in an integer and store it in four bytes: the two bytes of b, and whatever two bytes follow it in memory. (Well, technically this is undefined behavior, and no specific behavior is guaranteed; but that's what it's likely to do.) Apparently your compiler is using the two bytes after b as the first two bytes of m. Which is a bit surprising — I certainly wouldn't expect b and m to be adjacent, and it rather implies that your compiler isn't aligning shorts and ints to the beginning of four-byte blocks — but perfectly legal.

あなたが追加すれば、何が起こっているのかが分かります

printf("&a: %08X\n&m: %08X\n", (int)&a, (int)&m);

お互いに相対的に a m がどこに格納されているかを示します。 (ちょうどテストとして、私はあなたが "本当の"コードでそれを望んでいないことを意味する)。

2
追加された

正しいですが、%d int を予期して書き込みます。 65535 より小さい値を入力すると、 short 以外のバイトに収まるので、 a 戻る。私は short を読んでそれを元に戻そうとしました。私は 65536123 を入力して、 123 を得ました。65536は正確に16ビットを占め、残りの 123 short )。この動作は危険です。 short の他の2バイトは short の「隣の変数」になります。非常に悪いです。私はこれがあなたにそれをしないと納得させることを望む。

P.S. scanf short を読むには、一時的な int 変数を宣言し、 scanf short にキャストします。

2
追加された
一時的な int に格納する代わりに、 short int a scanf( "%hd"、&a);
追加された 著者 Joshua Green,
@moshbearそれは本当です - 私のコンパイラは、 "警告:format '%d'は 'int *'型を予期していますが、引数2に 'short int *'型があることを警告してくれました。"コンパイラの警告を無視することはトラブルのレシピです。
追加された 著者 dasblinkenlight,
技術的には、intを期待するときに int * 以外のものをscanfに渡すことはUBです。鼻の悪魔を喜ばせる人はいないでしょうか?
追加された 著者 moshbear,

変数 n を実際に使用していた場合は、 m ではなく、おそらくclobberedになっている可能性があります。 n を使用しなかったので、コンパイラはそれを最適化しました。つまり、 scanf()の書き込みで m (2バイトの代わりに(4バイト)整数へのポインタを持っていると言われたので)4バイト。これは、エンディアンやアラインメントなど、ハードウェアの詳細に大きく依存します( int を4バイトの境界に揃えなければならない場合は、問題は見えません; PowerPCやSPARCではなく、Intelのマシン上にいます)。

あなたのコンパイラには偶然にも疎通しないでください。それは自分自身を取り戻すでしょう。

1
追加された

非int to scanfの%dへのポインタを渡すとき、未定義の振る舞いを呼び出しています。

おそらく、コンパイラは、整列のためにパディングバイトを導入し、その値は「有効な」バイトではなくパディングバイトに格納されます。

しかし、コンパイラはsegfault/access違反を起こして鼻の悪魔を呼び出すことから自由に何でもできます。

1
追加された