1

私は本「Cのポインタを理解する」からいくつかの演習を行っています。この本はコードの一部を提供し、出力で何が得られるかを尋ねます。

それらの1つは次のとおりです。

#include <stdio.h>

int main(int argc, char* argv[])
{
    char c, *cc;
    int i;
    long l;
    float f;

    c = 'Z';
    i = 15;
    l = 77777;
    f = 3.14;
    cc = &c;
    printf("c=%c cc=%u\n", *cc, cc);
    cc = &i;
    printf("i=%d cc=%u\n",*cc,cc);
    cc=&l;
    printf("l=%ld cc=%u\n",*cc,cc);
    cc=&f;
    printf("f=%f cc=%u\n",*cc,cc);
    return 0;
}

出力は次のとおりです。

c=Z cc=1946293623
i=15 cc=1946293616
l=4294967249 cc=1946293608
f=0.000000 cc=4294967235

理由 がわかりませんlfとして印刷されませ777773.14?

printfの制御文字が正しいかどうかを確認するために C プログラミング言語という本を調べましたが、正しいです。

4

5 に答える 5

3

ブライアンの答えが言うように、渡される引数の型はprintf、フォーマット文字列で指定された型と一致する必要があります。

ポインタ値を表示する形式は"%p"-- で、void*引数が必要です。別の型のポインターは、明示的に にキャストする必要がありますvoid*

型が一致しないため、プログラムの動作が未定義です。また、キャストなしで互換性のないポインター型を割り当てようとするため、制約違反もあります。cc = &i;は違法です (ただし、コンパイラは、選択した場合に警告するだけです)。コンパイラからいくつかの警告が表示されるはずです。

そのプログラムの意図が、何をしてはいけないかを示すことであることを願っています。ステートメントの前の最後の 2 行だけを考えてみましょう。return

cc=&f;
printf("f=%f cc=%u\n",*cc,cc);

cc = &f;制約に違反しており、診断が必要です (IMHO の優れたコンパイラは致命的なエラーを発生させ、プログラムを拒否するはずです)。&fタイプfloat*でありcc、タイプchar*です。これらの型は代入互換ではありません。

そのステートメントを受け入れるほとんどのコンパイラは、それが暗黙の変換を意味すると想定しているため、合法的ですがトリッキーと同等になります。

cc = (char*)&f;

これにより、オブジェクトccの最初のバイトがポイントされます。floatf

printf("f=%f cc=%u\n",*cc,cc);

これは の値を出力すると主張していますがf、そうではありません。charを指すオブジェクトの値を出力しますcc。これはたまたまの最初のバイトですf。そして、未定義の動作を持つ%fそのオブジェクトのフォーマットを使用します。char結果はゴミ。

私はそのプログラムの「修正」版を書こうとしていましたが、問題が多すぎて、何を意図しているのかさっぱりわかりませんでした。

The C Programming Languageという本をチェックして、printfの制御文字が正しいかどうかを確認しました。

いいえ、そうではありません。または引数"%f"を出力するのは正しいですが(このコンテキストでは に昇格されます)、引数を渡しています。floatdoublefloatdoublechar

これは正しいでしょう:

printf("*cc = %d, cc = %p\n", *cc, (void*)cc);

しかし、同じことはしません。が指す文字ccを an として出力しint(文字として出力するために使用できますが%c、出力できない可能性があります)、次に の値をccポインターとして出力します。

本がこのプログラムについて何を述べているかを見るのは興味深いでしょう。

于 2013-04-22T15:04:09.363 に答える
2

printfの(さらに悪いことに)の書式指定子はscanf、パラメーターとして渡される型と一致する必要があります。使用している場合はgcc、オプションを使用する-Wallと、これに関する警告も表示されます。コードは次のようになります。

printf("c=%c cc=%u\n", *cc, (unsigned int)cc);
cc = &i;

の住所を解釈にi取り入れるchar*ことはもはや意味がありません。また、以下の他のものについても同様です。ポインターを割り当てることにより、同じビット表現の間違った解釈を強制します。

于 2013-04-22T14:42:11.077 に答える
1
printf("l=%ld cc=%u\n",*(long*)cc,cc);
printf("f=%f cc=%u\n",*(float*)cc,cc);

これは機能しますが、

printf("l=%ld cc=%u\n",*cc,cc);
printf("f=%f cc=%u\n",*cc,cc);

これは、次の理由により期待どおりではありません。

すべてのポインターは 4 バイト (それが指している場所ではなく OS に依存します) であるため、 float のアドレスでさえ char * に格納できます。ポインタ演算を行うとき、またはポインタの値を読み取るとき、ポインタ*ccのタイプに基づいて文字数を読み取ります...

文字が 2 バイトであると仮定すると、float または long 数が 4 バイト (またはそれ以上) に格納されているため、*ccアドレスを持つ 2 バイトのみが読み取られます。ccしたがって、無効なデータが表示されます。

それを型キャストすると*(long*)cc、明示的な型キャストで長いポインターとして扱われます。

于 2013-04-22T14:59:00.450 に答える
1

あなたのプログラムには多くの問題があります!!!

%uまず最初に、ポインターに書式指定子を使用しないでください。本質的に同じサイズである必要はありません.Always unsigned integersuse for .Egpointers%ppointers

printf("c=%c cc=%p\n", *cc, cc);

2番目に重要なこと--YKによる「Understanding pointers in C」という本を絶対に使用しないでください(明らかな理由により、著者の名前を完全には言えません)。彼の他の本は、SOの「void main」本として有名です。

3 番目に、あなたのプログラムに戻って、キャストなしで整数変数と浮動小数点変数のアドレスを文字ポインターに割り当てているときに警告が表示されなかったことに驚いています。.これは、指定された場所から解釈するバイト数をプログラムが認識できないため、エラーが発生することは間違いありません。int、、floatおよびcharサイズが異なります。そして、なぜエラーが発生しなかったのか不思議に思うかもしれませんint。右?これは、コンピューターのリトル エンディアン アーキテクチャが原因で、最下位バイトが最初に格納されます。

だからここにあなたの修正があります:

cc =(char*) &i;
printf("i=%d cc=%p\n",*(int*)cc,cc);
cc=(char*)&l;
printf("l=%ld cc=%p\n",*(long*)cc,cc);
cc=(char*)&f;
printf("f=%f cc=%p\n",*(float*)cc,cc);
于 2013-04-22T14:59:11.860 に答える