putchar() や fputc() といった関数は 非負整数1バイトを出力するわけですが、なぜ引数が int なのでしょうか。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
C言語の歴史を遡っていくと、かつてはプロトタイプ宣言がありませんでした。そして、そういうプロトタイプのない関数へ渡す引数は、int
未満であれば自動でint
に変換される、という既定の実引数拡張が行われていました。つまり。char
を渡してもint
を渡したのと同じことになっていました。
その後、プロトタイプ宣言ができたのですが、従来通りの挙動(int
を渡しても問題なく動く)とするために、仮引数の型はchar
ではなくint
となっている、ということのようです。
投稿2017/06/10 00:37
総合スコア145184
0
ベストアンサー
maisumakunさんがおっしゃっている通り、これは遺産/歴史によるものです。
C90標準の前には関数のプロトタイプ宣言はなく、全ての関数の全ての引数は Default promotion rules(既定の実引数拡張)の対象だったため、char は自動的に int として渡されました(shortはintに、floatはdoubleにというように)。標準は、既存のコードとの互換性を保つために、これらの関数の引数型をそのまま残しています。
この場合、引数型は int ですから、Integer promotionsというルールに則っています。
Integer promotions についての記述は §6.3.1 にあります。
¶2 The following may be used in an expression wherever an int or unsigned int may be used:
An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
A bit-field of type _Bool, int, signed int, or unsigned int.
If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.58) All other types are unchanged by the integer promotions.
¶3 The integer promotions preserve value including sign. As discussed earlier, whether a 'plain' char is treated as signed is implementation-defined.
- The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses.
投稿2017/06/10 05:32
総合スコア48
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
これは、メモリー上の変数の場所(アドレス)がint型のサイズ(2バイト/4バイト)に整列されるという、C言語の仕様によるものです。これはバイトアライメントと呼ばれる仕様で、PCのメモリーアーキテクチャに深く依存した話になります。
関数呼び出しの際、引数となる変数はスタックメモリー上に並べて配置され、関数側に制御が渡されることになります。この時、スタックメモリー上にアロケートされる引数の領域もまたバイトアライメントの原則に従う必要があります。(あなたが従うのではなく、Cコンパイラーがそのようにコードを生成する必要がある、という意味です。)C言語仕様にはこのことが関数引数のint型への暗黙的変換として定義されています。
変数領域のアライメントについては、以下のようなプログラムを実行してみると、確認することができます。
C
1#include <stdio.h> 2void f(int i, char c); 3int I1 = 0; 4char C1 = 0; 5int I2 = 0; 6char C2 = 0; 7 8int main() { 9 f(1, 2); 10 return 0; 11} 12 13void f(int argi, char argc) { 14 int i1 = 0; 15 char c1 = 0; 16 int i2 = 0; 17 char c2 = 0; 18 19 printf("&I1 = 0x%lx, &C1 = 0x%lx, &I2 = 0x%lx, &C2 = 0x%lx\n", &I1, &C1, &I2, &C2); 20 printf("&i1 = 0x%lx, &c1 = 0x%lx, &i2 = 0x%lx, &c2 = 0x%lx\n", &i1, &c1, &i2, &c2); 21 printf("&argc = 0x%lx, &argi = 0x%lx\n", &argc, &argi); 22} 23 24/* 25 * 外部変数、ローカル変数、引数変数のすべてのアドレスが4の倍数になっていることが確認できます。 26 * これはつまり、C1やc1、argcなどの変数は1バイトの領域しか使用しないにもかかわらず、 27 * 隣の変数の領域との間を3バイト分のパディング領域で埋めることでバイトアライメント 28 * の原則が維持されていることを示しています。 29 */
さて、上記のように char 型の引数は暗黙的に int 型として処理されているわけですが、ではなぜ putchar() や fputc() の引数が int 宣言されているのでしょうか。暗黙的な型変換が自動的に行われるのであれば、これらの標準関数のプロトタイプも putchar(char c) で良いのでは?ということになりますね。
これに関しては、C言語の古い仕様(C90よりも前の仕様)では、プロトタイプ宣言という機能が無かったことと、大昔のC言語はint型が2バイト長だったことが関係していると言われています。
プロトタイプ宣言機能が無かった頃、putchar()やfputc()の引数に char ではなく、int を渡すようなコードが多数存在していました。これは、当時のプログラマーがPCのメモリーアーキテクチャやC言語のバイトアライメントに関する仕様に対して、熟知しているがゆえに、暗黙的な型変換の仕組みを「気持ち悪い」と感じていたことと、1バイトの文字を保持するのに int 型を使うことに違和感を感じなかったからではないかと想像できます。
標準関数のプロトタイプが決められる過程で、既存のコードに char 型変数とに暗黙の型変換を強制するよりも、バイトアライメントの原則に従い、int型の引数とするほうが、より自然であると判断されたのには、このような背景があったのではないでしょうか。
ご参考になれば。
投稿2017/06/10 01:54
総合スコア2425
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/06/10 04:35
2017/06/10 04:38
2017/06/10 04:50
2017/06/10 05:08
2017/06/10 05:22
0
EOF を表す為です。unsigned char の 0~255 では -1 は表現できないですからね。
投稿2017/06/10 03:56
編集2017/06/10 03:57総合スコア5030
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/06/10 04:06
2017/06/10 04:14
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。