• 締切済み

C言語 プロトタイプ宣言のスコープ

現在、C言語の勉強中です。 プロトタイプ宣言は関数内で宣言をすることは可能でしょうか。 その際、宣言が有効なのはその関数内ということになりますか? OS:windows7 VS2010 express で次のプログラムを記述してもコンパイルエラーにはなりませんでした。 もし、プロトタイプ宣言もスコープを持つとしたら、関数plus()の中でminus() を呼び出したところでwarningかエラーをはくと考えましたが、出ませんでした。 どなたか、教えてください。 #include <stdio.h> int main(void){ char* plus(void); //プロトタイプ宣言 char* minus(void); // char *ans; ans = plus(); printf("mainFunc = %s", ans); ans = minus(); printf("mainFunc = %s", ans); } char* plus(){ char *answer; //関数の戻り値はポインタ answer = minus(); //プロトタイプ宣言なしで関数を使用 printf("plusFunc = %s",answer); return "plus success\n"; } char* minus(){ return "minus success\n"; }

みんなの回答

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.7

>LinuxやUnixの環境でテストしなくては >ダメということですね。 どういう事でしょう? もしかしてコンパイル時に警告やエラーが起きないことで、自分のコーディングが正しいかの判定をしようとしてますか? もしそうなのでしたらコンパイル時にエラーや警告もなく、実際に実行して意図した動作をしたとしても、コーディングは間違っている場合もありますのでお気を付けください。 よくあるのはNULLと0の混同。

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

同意>#5. あの会社は正直なところ「『C++ があるんだから, もう C なんかど~でもいいじゃん』って考えてるんじゃないか」と思えるときがある. 未だに C99 にすら対応してないくらいだし. ちなみに今回の話は「関数へのポインタ」とは全くもって無関係です>#4.

tama_sampo
質問者

お礼

LinuxやUnixの環境でテストしなくては ダメということですね。 ありがとうございました。

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.5

>Cのスコープって実際にはコンパイラによって違うんですね。 >っていうか。。。結構、いいかげんなものなのでしょうか? 「VC++のCコンパイラモードでのスコープの扱いはおかしい」という話だと思うんですが・・・ 「いいかげんなのはVC++のCコンパイラモード」といった方がわかりやすいですか?

tama_sampo
質問者

お礼

私の言いたかったことを正確に表現して いただいてありがとうございました。 表現力が乏しくてすみません。。。

回答No.4

まったく違う話になります。 私はこれを見たとき、関数ポインタに見えてしまって。 一緒に勉強してもらえたらと思って、回答してみました。 char hoge() { return ('A'); } main () { char *abc(); abc=hoge; abc(); // この場合、abcは関数のプロトタイプではなく、char (*abc)();というポインターそのもの。 } 多分この書式のせいで、コンパイラーによって、問題が出るのかもしれません。。 正式なプロトタイプは char* plus(void);//プロトタイプ宣言 なら、 typedef char * (FUNC)(void); ということで、これらが問題を起こしているのかも、と 私はちょっと、推測してしまいました。

tama_sampo
質問者

お礼

勉強になりました。 ありがとうございました。 関数のポインタ宣言は私のコンパイラでは char *abc() //エラー char (*abc)() //OK でした。こちらも環境依存かも? あわてて、勉強したので返信がおそくなってしまいました。

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

あ~, たぶんわかった. C において 1つのプログラムに「同じ外部名を持つ実体」は 1つしか存在できない. だから, 当該プロトタイプの「本来のスコープ」から外れても「その外部名である以上それだ」と判断できるってことじゃないかな. ちなみに gcc だと (こっちは逆にスコープを「正しく」判断した結果として) エラーになりますね. そして main と plus を入れ替えると VC はアホなエラーメッセージを出しやがる. #2 の話は, おそらく単純なバグ.

tama_sampo
質問者

お礼

ありがとうございました。 Cのスコープって実際にはコンパイラによって違うんですね。 っていうか。。。結構、いいかげんなものなのでしょうか?

回答No.2

main関数を少し変えて、 #include <stdio.h> int main(void){ char* plus(void);//プロトタイプ宣言 int minus; { char* minus(void);// char *ans; ans = plus(); printf("mainFunc = %s", ans); ans = minus(); printf("mainFunc = %s", ans); } minus=-1; } これでも、文法違反はないはずですが、Visual StudioのCコンパイラではエラーになります。 同じVisual StudioのC++コンパイラを使うとエラーにはなりません。Cコンパイラのバグかもしれません。

tama_sampo
質問者

お礼

ありがとうございました。 cygwinのgccでいただいたsampleのコードをコンパイルしました。 おっしゃる通りエラーはなく実行できました。 こちらはVSのcコンパイラのバグだと理解しました。 mainの中のブロック内で宣言したプロトタイプのスコープは 予想通りでしたが、なぜmain直下に記述したプロトタイプは main外の関数で有効になるのでしょうか? しつこくて、すみません。 #include <stdio.h> int main(void){ char* plus(void);//プロトタイプ宣言 //char* minus(void); //ここで宣言した場合はmainの外でも有効? int minus; { char* minus(void);//ここで宣言したので、当然、plus()では無効 char *ans; ans = plus(); printf("mainFunc = %s", ans); ans = minus(); printf("mainFunc = %s", ans); } minus=-1; } char *plus(){ char *minus(void);//再度、プロトタイプ宣言 char *ans; ans = minus(); printf("%s", ans); return "plus\n"; } char *minus(){ return "minus\n"; }

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

そもそも C ではプロトタイプなしで関数を呼び出してもエラーにはなりません. でもって, プロトタイプ宣言自体は「普通の」規則に従ったスコープを持ちます.

関連するQ&A

  • C言語 プロトタイプ宣言

    分割コンパイルした場合のプロトタイプ宣言について質問です。 以下のプログラムをコンパイルすると警告がでます。 プロトタイプ宣言は関数を利用する側と定義側両方に必要と理解していたのですが・・・ どなたか教えていただけますでしょうか。 windows7 cygwin gccでコンパイル エラーメッセージ $ gcc -o testMain.exe testMain.c testKioku.c testKioku.c:9: 警告: conflicting types for 'func1' testKioku.c:3: 警告: previous declaration of 'func1' was here testKioku.c:17: 警告: conflicting types for 'func2' testKioku.c:4: 警告: previous declaration of 'func2' was here ソース testMain.c #include <stdio.h> void func1(void); void func2(void); int cnt=5; main(){ printf("main=%d\n",cnt); func1(); func2(); } testKioku.c #include <stdio.h> void func1(void); void func2(void); extern int cnt; func1() { cnt++; printf("func1 global cnt=%d\n",cnt); func2(); } func2() { printf("func2 global cnt=%d\n",cnt); }

  • プロトタイプ宣言について

    C言語で関数を作成しプロトタイプ宣言するときの質問です。 関数実体の引数に構造体のポインタを宣言します。 プロトタイプ宣言には,構造体のポインタを宣言したのと同じ位置にvoid *を宣言します。 関数実体とプロトタイプ宣言は,異なるファイルです。 このように作成した関数は,VC++2008では,コンパイルできるのですが, なぜ関数実体の宣言とプロトタイプ宣言の型が異なるのにコンパイルできるのでしょうか? また,この関数を別ファイルの関数から呼び出した場合,正しく引数を理解し,正しく処理されます。 これは,言語仕様として正しい書き方なのでしょうか? それとも環境依存の書き方なのでしょうか? ご存知の方がいましたらお答えお待ちしています。

  • C言語/プログラミング

    秒を%d時間%d分%d秒に変換するプログラミングを教えてください。計算でちょっと積んでます... [現在のプログラミング] #include <stdio.h> void Time(int s) { int ans1, ans2; printf("秒を入力してください\n"); scanf_s("%d", &s); ans1 = s / 3600; ans2 = s / 60; printf("[計算結果]%d秒 = %d時間%d分%d秒\n", s, ans1, ans2); return 0; } int main(int s) { Time(0); return 0; }

  • C言語

    #include <stdio.h> int main(void) { int a=0,ans1,ans2,ans3,ans4; printf("整数を入力してください。\n"); scanf("%d",a); ans1 = a+7; ans2 = a*;8 ans3 = a%3; ans4 = a*(-1); printf("%d\n",ans1); printf("%d\n",ans2); printf("%d\n",ans3); if(a==15){ prntf("true\n",a); } else{ printf("false\n",a); } if(a != 8){ printf("true\n",a); } else{ printf("false\n",a); } if(a <= 3){ printf("true\n",a); } else{ printf("false\n",a); } printf("%d\n",ans4); if(a<2||7<a){ printf("true\n",a); } else{ printf("false\n",a); } return 0; } これを実行しようとしてもexeファイルになりません。 教えていただけませんか?

  • C言語のエラー処理について

    下記のコードを作成したのですが、入力エラーの際に出力される表示が意図した input error の出力と違う形で表示されてしまい、修正方法が分からず、どなたか教えて頂けないでしょうか? ・『あ』等の整数以外の文字が入力された時 input errorinput errorinput error ・/0が入力された時 input error input error input error 「ソースコード」 #include <stdio.h> #include <time.h> #include <string.h> #include <stdlib.h> #define CALC (3) #define FROM_YEAR (1900) #define MAX_LINE (1000) #define MAX_ROW (1000) float calc_proc(int* n1, char op, int n2, float* ans) { switch (op) { case '+': *ans = (float)*n1 + n2; break; case '-': *ans = (float)*n1 - n2; break; case '*': *ans = (float)*n1 * n2; break; case '/': if (n2 == 0) { puts("input error"); return 1; } *ans = (float)(float)*n1 / n2; break; default: printf("input error"); return 1; break; } return 0; } int cmp_u(const void* a, const void* d) { return strcmp((char*)a, (char*)d); } int cmp_d(const void* a, const void* d) { return strcmp((char*)d, (char*)a); } int main() { int num1, num2; char op; float answer; int i; FILE* fp; char e[11]; char sin[MAX_LINE][MAX_ROW]; char ad[8]; fp = fopen("log.txt", "a+"); if (fp == NULL) { printf("ファイルオープン失敗\n"); return -1; } while (1) { scanf("%d%c%d", &num1, &op, &num2); calc_proc(&num1, op, num2, &answer); if (calc_proc(&num1, op, num2, &answer) != 0) { puts("input error"); return 1; } time_t t = time(NULL); struct tm* tm = localtime(&t); printf("%d/%02d/%02d ", tm->tm_year + FROM_YEAR, tm->tm_mon + 1, tm->tm_mday); printf("%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); printf("%d%c%d,%f\n", num1, op, num2, answer); fprintf(fp, "%d/%02d/%02d ", tm->tm_year + FROM_YEAR, tm->tm_mon + 1, tm->tm_mday); fprintf(fp, "%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); fprintf(fp, "%d%c%d,%f\n", num1, op, num2, answer); printf("計算を続けますか?"); scanf("%s", e); if (strcmp(e, "no") == 0) { break ; } } fclose(fp); fp = fopen("log.txt", "r"); if (fp == NULL) { printf("ファイルオープン失敗\n"); return -1; } int cnt = 0; for (i = 0;i < MAX_LINE;i = i + 1) { if (fgets(sin[i], sizeof(sin[0]), fp)) ++cnt; else break; } fclose(fp); printf("ASC or DESC: "); scanf("%s", ad); if (strcmp(ad, "ASC") == 0) { qsort(sin, cnt, sizeof(sin[0]), cmp_u); } else { qsort(sin, cnt, sizeof(sin[0]), cmp_d); } for (i = 0;i < cnt;i = i + 1) { printf("%s", sin[i]); } return 0; }

  • プログラム実行

    下記のプログラムを実行したら、 「警告 W8065 random01.c 15: プロトタイプ宣言のない関数 'strcat' の呼び出し(関数 ma in ) エラー E2342 random01.c 15: パラメータ '__path' は const signed char * 型として 定義されているので int は渡せない(関数 main ) 警告 W8065 random01.c 34: プロトタイプ宣言のない関数 'strcmp' の呼び出し(関数 ma in ) 警告 W8065 random01.c 34: プロトタイプ宣言のない関数 'strcmp' の呼び出し(関数 ma in )」 と表示されました。どこを改善すればうまくいきますか? OSはWinXPでコンパイラはボーランドのフリーコンパイラを使用しています。 #define RECORDLEN 33 #include <stdio.h> #include <stdlib.h> int main() { FILE *fp; char fname[256], data[16], ans[8]; int no; printf("ファイル名"); fp = fopen(strcat(gets(fname), ".txt"), "r"); if (fp == NULL) { perror("ファイルがオープンできません\n"); return -1; } while (1) { printf("何人目のデータを読み込みますか---"); gets(ans); no = atoi(ans); fseek(fp, RECORDLEN * (no - 1), SEEK_SET); if (fscanf(fp, "%s", data) == EOF) { perror("読み込みエラーです\n"); continue; } printf("[氏名] %s", data); fscanf(fp, "%s", data); printf("[電話] %s\n", data); printf("続けますか(y/n): "); gets(ans); if (strcmp(ans, "n") == 0 || strcmp(ans, "N") == 0) break; } fclose(fp); return 0; }

  • C言語_関数宣言_fprintfです!お願いします!!

    C言語(C言語_関数宣言_fscanf)に関する質問です。 main関数とは別に新しく自分で関数を定義しました。 (keisan関数とします。) keisan関数の中に「fprintf」を用いたのですが上手くいきません。 (printfは通常通りに働きます。) どのような理由が考えられるでしょうか? (グローバル変数などの理由でしょうか?) どうか,ご指導お願いします!! #include <stdio.h> void kiroku(int ki1,int ki2){ printf("%d-%d\n",ki1,ki2); fprintf(fo,"%d-%d\n",ki1,ki2); /*↑このfprintfです*/ } int main(){ char *fnmo="kiroku.txt"; FILE *fo; int n,i; // open files. fo = fopen(fnmo,"w"); if(fo==NULL) { printf("NG\n"); return 0; } // read and store. n=1; i=2; kiroku(n,i); // close files. fclose(fo); return 0; }

  • C言語のint型の配列が分かりません

    #include<stdio.h> int main(void) { int str[ ]={0,1,2} printf("%s\n", str); return 0; } というプログラムをC言語でつくってみましたが動きません.(012と表示されて欲しかったのですが) int str[ ]={1,2,3}の部分をchar str[ ]={'0','1','2'}とすれば動きます. そこで質問なのですが, printf("~%s~", (配列名));  はchar型の配列にしか適応できないのですか? ※追記 puts関数の定義は int puts (const char *str); であるそうなので char型の仮引数にはchar型のアドレスを渡さなければいけません. ではprintf関数の定義は一体どんなものなのですか?

  • C言語の穴埋め問題なのですが

    ???の中身を教えてください #include <stdio.h> #define N 3 //構造体の宣言 typedef struct date{ char *nengou; int year; int month; int day; }DATE; //関数のプロトタイプ宣言 void disp(DATE data); int main(void) { DATE birthday; char buff[80]; ???= buff; printf("年号:"); scanf("%s" , birthday.nengou); printf("年:"); scanf("%d" ,&birthday.year ); printf("月:"); scanf("%d" , &birthday.month); printf("日:"); scanf("%d" ,&birthday.day ); disp(birthday ); } void disp(DATE data) { printf("%s%d年%d月%d日\n" , data.nengou , data.year , data.month , data.day); }

  • C言語の穴埋め問題です

    次のプログラムは、初期化により文字列を定義し、辞書式配列にしたとき、どの文字列が先頭にくるかを調べるプログラムなのですが。■■■を教えてください #include <stdio.h> #include <string.h> #define N 5 //関数のプロトタイプ宣言 char *min(char *p[] , int n); int main(void) { char *p[N] = {"Hello" , "Hi" , "Happy" , "HaHaHa" , "Heaven"}; printf("辞書式配列で先頭となる文字列は%s\n" , ■■■); } char *min(char *p[] , int n) { int min; //最小値のアドレス Int i; //カウンタ min = 0; for(i = 1; i < n; i++){ if (strcmp(■■■ , ■■■) > 0){ ■■■= ■■■; } } return ■■■; }