• ベストアンサー

なぜgccはstdio.hをインクルードしなくてもprintfが実行できるのか

なぜgccはstdio.hをインクルードしなくてもprintfが実行できるのでしょうか。 暗黙にインクルードされるヘッダと されないヘッダファイルの差分等あれば教えていただきたく。。 // main.c int main(){ printf("SWSW\n") ; return 0 ; } % gcc main.c % ./a.out SWSW

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

ごくおおざっぱに言えば、インクルードファイルの中には、 ・グローバル変数 ・typedef による型の定義 ・sturcut や union や enum などユーザー定義の型(の定義) ・#define によるマクロ ・関数プロトタイプ があります(その他のものもあります) この中で、関数プロトタイプをのぞけば必須です。 ですから、NULL や EOF を使うには、(別に定義するのでなければ) stdio.h が必要です(だったかな?) assert の実体は(関数ではなくて) #define によるマクロだった気がします(未確認・だとしたらインクルードは必須ですね) さて、printf() の件ですが、これは、 printf("SWSW\n"); だったから(2番目以降の引数がないから)たまたま実行可能だったという可能性があります。 printf() は、可変引数(引数の数が決まっていない)関数なので、プロトタイプがないと、うまく処理できないコンパイラが多いです。 その場合でも、最初の引数の型決まっているので、引数がひとつだと、たまたま正常に実行可能です。 printf("%d, %f, %s", 1, 0.1, "STR"); なんかだとうまく処理できますでしょうか? (これも未確認) あと、関数の返値の型が int でないものは、プロトタイプがないと変な値が帰ってきます。 (ちなみに、printf() の返値は int です。あまり使われませんが)

その他の回答 (7)

  • mamaoni
  • ベストアンサー率23% (3/13)
回答No.8

先ほど、リナックスの参考書を見てみると、print()関数は、内部でシステムコールを使っているとありました。 カーネルと結びつけられているからでは、ないでしょうか?

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.7

> ”可変個引数を持つ関数を関数原型なしで呼び出した場合の動作は未定義”というのはどこで規定されているものなのでしょうか(C90?)。 JIS X3010:2003の「6.5.2.2 関数呼出し」の項には、 「呼び出される関数を表す式が,関数原型を含まない型をもつ場合,各実引数に対して整数拡張を行い,型floatをもつ実引数は型doubleに拡張する。この操作を既定の実引数拡張(default argument promotion)と呼ぶ。実引数の個数と仮引数の個数が等しくない場合,その動作は未定義とする。関数原型を含む型で関数を定義し,かつ,関数原型が省略(, ...)で終わっている場合,又は拡張後の実引数の型が,仮引数の型と適合しない場合,その動作は未定義である。」 という記述があります。

cafe2cafe
質問者

お礼

対応いただきありがとうございます。 納得しました。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.6

Cでは、関数原型(プロトタイプ)が宣言されていない状態でも関数を呼び出すことができます。しかし、printfのような可変個引数を持つ関数を関数原型なしで呼び出した場合の動作は未定義です。動作が未定義の場合、特定の振る舞いをするように処理系を実装しても構わないので、GCCではまともに実行できるというだけです。 assertは、既に回答が出ているようにマクロですので、<assert.h>を必ずインクルードしなければなりません。

cafe2cafe
質問者

お礼

ありがとうございます。 assertについてはマクロ実装との事で理解しました。 ”可変個引数を持つ関数を関数原型なしで呼び出した場合の動作は未定義”というのはどこで規定されているものなのでしょうか(C90?)。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

既に書かれているように, assert は assert.h で定義されるマクロです (というか, assert の機能をマクロ以外で実現する方法が存在しない)... と規格に書いてある. だから, assert.h を #include しないと使えません.

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.3

> assert関数は<assert.h>をincludeしないとコンパイルエラーになる どういったコンパイルエラーが出ますか?

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

1つは C ではプロトタイプ宣言が必須ではないこと, もう 1つは勝手に (printf などの実体の入っている) libc をリンクするから, かな. ちなみにプロトタイプ宣言がない関数を呼び出した場合, 型 int()(...) をもつと仮定されるんじゃなかったかな.

cafe2cafe
質問者

お礼

回答ありがとうございます。 プロトタイプ関数が必須でない事、libcに含まれているという事で理解しましたが、 assert関数は<assert.h>をincludeしないとコンパイルエラーになるのですが、この差分は何になるのかご存知でしょうか。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

>なぜgccはstdio.hをインクルードしなくてもprintfが実行できるのか 単に printf() の関数宣言をチェックしていないだけでしょう。

関連するQ&A

  • #include <stdio.h>

    #include <stdio.h> struct st { char a[3]; short b; char c[7]; long d; char e[5]; }; int main(void) { printf("%d\n",sizeof(struct st)); return 0; } コンパイルオプションでアライメントを変化させながら(1,2,4,…) sizeof(struct st)の変化を見たいのですが、コンパイルする時に どのようにすれば良いのでしょうか?当方、gccを使用しております。 あと、ついでなんですが、警告オプションは-Wと-Wallしかないのでしょうか?

  • #include<stdio.h>

    #include<stdio.h> main () { int a,b; printf("適当な数字\n"); scanf("%d %d",&a,&b); printf("(a*b)%(a+b)=%d\n",(a*b)/(a+b)); return (0); } で結果が 任意の数字 2 3 (a*b)(a+b)=1 ん なんですが違いますよね? 商の余りを求めるにはどう改変すればいいでしょうか?

  •    #include<stdio.h>

       #include<stdio.h> #include<math.h> int main(void) { int i,n,limit; printf("data? "); scanf("%d",&n); i(n>=2){ limit=int)sqrt(n); for(i=limit;i1;i--){ if(n%i==0) break; } if(i==1) printf("素数\n); else printf("素数でない\n"); } return 0; } というプログラムがあるのですが、それを改良して int型(符号付32ビット整数)および、unsigned int型(符号なし32ビット整数)のそれぞれの最大の素数を求めよという問題があり、ただし、エラトステネスのふるいは使わずに、上のプログラムを改良してみよという問題がどっかにあったんですが、全然わからないので、教えてください。

  • Visual C++ 2008で<stdio.h>のインクルード文が使えない!?

    #include <stdio.h> int main(){ printf("hello!"); } で実行すると、 : warning C4627: '#include <stdio.h>': プリコンパイル済みヘッダーの使用を検索中にスキップされました ディレクティブを 'stdafx.h' に追加するか、プリコンパイル済みヘッダーをビルドし直します .\■■■.cpp(5) : fatal error C1010: プリコンパイル ヘッダーを検索中に不明な EOF が見つかりました。'#include "stdafx.h"' をソースに追加しましたか? と言ったエラーが起きてしまいます。 ちなみに、インクルードファイルらしき物を削除しまくった覚えがあります…。100%これが原因かと。 これが原因だとしたらどうすればいいんでしょうか? あと、DXライブラリが使えるように設定を変えたこともあります。 どこの何を変えたかは忘れてしまいましたけど。

  • printf()関数の括弧を二重にして、printf((~~~))とし

    printf()関数の括弧を二重にして、printf((~~~))として コンパイル/実行すると、実行時セグメンテーション違反が発生します。 コンパイル時には警告も発生しますが、このセグメンテーション違反が なぜ起こるのか理由がよくわかりません。ご回答いただけるとありがたいです。 以下、サンプルコードと実行例です。よろしくお願いいたします。 ---mytest.c---- 1 #include <stdio.h> 2 3 int main(void){ 4 5 //printf("test:%d", 1)ではもちろんコンパイル/実行に成功する。 6 printf(("test:%d", 1)); 7 return 0; 8 } 【コンパイル/実行結果/gccバージョン】 #gcc main.c main.c:6:警告:passing argument 1 of printf makes pointer from integer without a cast #./a.out セグメンテーション違反です # gcc --version gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-27) ・ ・

  • printf scanf が、反応しません。

    printf scanf が、反応しません。 #include <stdio.h> int main(void) { int num = 0; int sum = 0; printf("テストの点数を入力してください。(0で終了)\n"); do{ scanf("%d", &num); sum += num; }while(num); printf("テストの合計点は%d点です。\n", sum); return 0; } C:\WORK>gcc test1.c C:\WORK>gcc -o test1 test1.c おかしいです。 打開策を教えてください。 ご多忙中恐れ入ります。 ご回答のほど、宜しくお願い申し上げます。

  • windowsのコンパイラーで正しく実行されたのに、gccのコンパイラーでエラーがでた

    windowsのコンパイラーで正しく実行されたのに、gccのコンパイラーでエラーがでたソースコードです。ファィル名test.c です。Linux(Red Hat9) gccです。windowsのコンパイラーはCPad for Borland C++Compilerです。 #include <stdio.h> void main() //intからvoidに変更した { int i, j; for (i=1; i<=9; i++){ printf("%2d ",i); //%2dで、iが2桁に表示 } printf("\n"); printf("***************************\n"); //この罫線もどきの書き方はダサいので工夫してください for (i = 1; i<=9; i++){ for (j = 1; j<= 9; j++) { printf("%2d ", i*j); if (j == 9) printf("\n"); //1行表示後改行 } } return; //voidにしたので0を取った! } これがLinux(RedHat9)gccでは以下のエラーが出ます。 (test.c: 関数 `main' 内: test.c:4: 警告: `main' の戻り値の型が `int' ではありません)  なぜ、同じソースコードでエラーが起こるのですか?  Linux gccでは、この場合`int' 以外の何が必要なのでしょうか? 以上よろしくお願いします。

  • printfの使い方

    #include <stdio.h> main() { printf("正しい?"); int a; int b; int c; printfをこのように使うと int がここでは 宣言できないとなってしまうのは何故ですか?

  • #include <stdio.h>

    #include <stdio.h> int main(void) { int num1,num2; int num3 = 5; printf("所持金を入力してください?"); printf("%d",&num1); printf("\n"); printf("購入品の金額を入力してください?"); printf("%d",&num2); printf("\n"); printf("\n"); printf("購入金額%d円\n", num2); printf("\n"); printf("消費税額%d円\n", num2 * num3/100); printf("\n"); printf("合計金額%d円です \n", num2 * num3/100+num2); printf("\n"); printf("お釣りは%d円です \n", num1-(num2 * num3/100+num2)); printf("\n"); printf ("内訳は \n"); printf("\n"); printf("10000円紙幣:%d枚 \n",(num1-(num2 * num3/100+num2))/10000); printf("5000円紙幣:%d枚 \n",(num1-(num2 * num3/100+num2))/5000); printf("1000円紙幣:%d枚 \n",(num1-(num2 * num3/100+num2)-5000)/1000); printf("500円硬貨:%d枚 \n",(num1-(num2 * num3/100+num2)-7000)/500); printf("100円硬貨:%d枚 \n",(num1-(num2 * num3/100+num2)-7000)/100); printf("50円硬貨:%d枚 \n",(num1-(num2 * num3/100+num2)-7200)/50); printf("10円硬貨:%d枚 \n",(num1-(num2 * num3/100+num2)-7250)/10); printf("5円硬貨:%d枚 \n",(num1-(num2 * num3/100+num2)-7270)/5); printf("1円硬貨:%d枚 \n",(num1-(num2 * num3/100+num2)-7275)/1);   printf("です。\n"); return 0; }  なんかエラー出ます・・・どこが間違ってるんでしょうか?

  • C言語でscanf()が先に実行されるのはなぜですか?

    C言語でscanf()が先に実行されるのはなぜですか? #include <stdio.h> int main(void){ int intNum; printf("整数を入力してください:\n"); scanf("%d", &intNum); printf("入力値は:%d\n",intNum); return(0); }

専門家に質問してみよう