プロが教える店舗&オフィスのセキュリティ対策術

c言語についての質問です.疑問と自分なりの解答を書くので訂正,アドバイスなどを頂けるとありがたいです.

以下のプログラムのようにprint関数でdoubleのフォーマットを%fとします.scanのフォーマットを%lfとします.問題なく通ります.しかし,scanの方のフォーマットを%fにすると
format ‘%f’ expects type ‘float *’, but argument 3 has type ‘double *’
と警告が出て,プログラムも正常にaに値を格納しません.なぜでしょう?

これは,変数ならfloat-double間の拡張をコンパイラが勝手にやってくれるが,ポインタの拡張は勝手にやれないから駄目,という理解でよろしいのでしょうか.

このことから,double変数の表示には%fでもいいが,%lfを常に使う方が正統な書き方だという理解でよろしいのでしょうか.常に%lfを使うと何か問題なのでしょうか.

お返事お待ちしております.

#include <stdio.h>
int main()
{
double a = 2.5;
char in_line[50];
fprintf(stdout, "a is %f\n", a);
fprintf(stdout, "type any double: ");
fgets(in_line, sizeof(in_line), stdin);
sscanf(in_line, "%lf", &a);
fprintf(stdout, "a is %f\n", a);
return 0;
}

A 回答 (1件)

まず、引数の数が変えられる「可変長引数」というのがあります。


scanfもprintfも可変長引数の関数です。
C言語の場合、この可変長引数は次の特徴があります
(1)引数として指定すると、int以下の整数はintに、double以下の実数はdoubleに型変換されます
(2)関数側では、どんな引数が指定されたか、知ることができません。

(1) はprintfの%f に関係があります。
float f;
double d;
printf("%f %f",f,d) ;
とあった場合、(1)のルールによって
printf("%f %f",(double)f,d) ;
と等価になります。
%fの対象をfloatとdoubleとで区別する必要がありません。
どちらもdoubeになるのですから


(2)はscanfの%fと関係します。
引数の型や数を知ることができないので、別な方法で知ります。
その方法の一つが、「別の引数で、数や型を指定する」というものです。
scanf,printfの場合、書式文字列中の %* の数と型で判断します。

scanf("%f", &d) ;
だと、 %f なので、1つのfloat * が指定されている、と判断します。つまり
scanf("%f", (float *)&d) ;
です。そして、読み込んだ値をsizeof(float)分、ポインタが示すアドレスに書き込みます。
一般にsizeof(float)<sizeof(double)なので、変数dの領域の一部が書き変わるだけです。
読み出した値は正しく変数dには納まりません。

scanf("%lf", &d) ;
だと、 %lf なので、1つのdouble * が指定されている、と判断します。つまり
scanf("%lf", (double *)&d) ;
です。そして、読み込んだ値をsizeof(double)分、ポインタが示すアドレスに書き込みます。
こちらは、型と内容が一致するので、正しく変数dに納まります。


一部コンパイラは、書式文字列と引数との対応を調べて警告を出しますが、書式文字列が変数で指定されている場合等では、警告も出ません。
char scanFormat[STRMAX] ;
/* scanFormatに書式文字列を設定 */
scanf( scanFormat, &a);


>double変数の表示には%fでもいいが,%lfを常に使う方が正統な書き方だという理解でよろしいのでしょうか
> 常に%lfを使うと何か問題なのでしょうか.

むしろ、%fの方が正統です。
もともとprintfに%lfは不要ですし、存在していませんでした。
ところが、scanfと混同して「%lfが正しい」と考える人があまりに多かったので、後から規格に追加されました。

C99以降の規格に準じたコンパイラなら、どちらを使っても同じです。
それ以前のコンパイラでも、独自に%lf=%fとして処理しているものもありますが、%fとして動作しない場合もあります。
http://www.kijineko.co.jp/tech/superstitions/pri …
    • good
    • 1
この回答へのお礼

ありがとうございます.説明していた内容をもとにprintf, scanfを読んだらとてもよく分かりました.今後もよろしくお願いします.

お礼日時:2013/11/09 00:51

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています