質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

1553閲覧

C言語のEOFについて

zakonokiwami

総合スコア5

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2020/06/11 09:02

お世話になっております。
早速、質問をさせて頂きます。

#include <stdio.h>

main()
{
int c;
c = getchar();
while (c != EOF)
{
putchar(c);
c = getchar();
}
}

Q1. EOF とはstdio.h が用意している定数ということ、EOF には -1 が定義されているという認識ですが、正しいのでしょうか。

Q2. getchar()、putchar() 関数は定義していなくてもエラーが発生せず使用できますが、なぜですか?
色々調べたのですが、コンパイラが準備している関数でコンパイルする際に使用できるようになるという曖昧な認識でいます。この場合、コンパイルして作られるオブジェクトコードには上記関数が追加されているということですか。

Q3. getchar()、putchar() 関数の中身の処理はどうなっているのか確認を行うことはできないのでしょうか。

Q4. 関数は定義する、変数は宣言すると宣言と定義の使い分けはあってますか。

以上、宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

EOF とはstdio.h が用意している定数ということ、EOF には -1 が定義されているという認識ですが、正しいのでしょうか。

前者のみ正しいです。EOFの実際の値は、負であること以外は処理系定義です。

getchar()、putchar() 関数は定義していなくてもエラーが発生せず使用できますが、なぜですか?

#include<stdio.h>の中に宣言(もしマクロだったとしたら定義)が書かれています。

getchar()、putchar() 関数の中身の処理はどうなっているのか確認を行うことはできないのでしょうか。

標準ライブラリのソースコードがコンパイラに付属しているのでしたら、そちらをご確認ください。

関数は定義する、変数は宣言すると宣言と定義の使い分けはあってますか。

違います。宣言と定義はそれぞれ別な意味を持っています。関数の宣言だけ行うこともあります。

投稿2020/06/11 09:11

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Q1.EOFは(−1)と定義されている場合が多いです。実際はWindowsならctl+z,Unix系ならctl+dでOSから通知を受けます、それをライブラリが-1(0xFFFFFFFF)として通知してくるだけです。(なのでgetchar()の復帰値がintになっている訳です。
Q2,Q3.ワーニングは出ると思いますが?内部については処理系依存なのでデバッガで追いかけましよう
・・・アセンブラになると思いますが・・・

text

1ts.c:4:4: warning: implicit declaration of function 'putchar' is invalid in C99 [-Wimplicit-function-declaration] 2 putchar('\n'); 3 ^ 41 warning generated. 5usr ~/Project/test % cat ts.c 6 7int main(void) 8{ 9 putchar('\n'); 10 11 return 0; 12}

投稿2020/06/11 09:14

編集2020/06/11 09:20
cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

cateye

2020/06/11 10:12

ptchar()がエラーにならないのは、過去、未定義な関数はintを返すとしてコンパイルできたからだと思います。 ・・・あんまり自信なし^^;・・・
zakonokiwami

2020/06/12 02:28

ご返信頂き、誠にありがとうございます。 デバッガ機能について調べてみます。 調べているとビジュアルスタジオがでてきました。 コンパイル機能もあり、デバッグ機能もありですごいですね! C++でもCは動くみたいで、、、ちょっとすみません。 脱線しそうなので、ここまでにしてまたわからなくなったら質問します(笑) デバッガ(デバッグ)についてもっと調べてみたいと思います。
guest

0

ベストアンサー

A2.
一般的な使われ方として、「C言語ソースをコンパイルする」「実行可能なバイナリファイルを作る」は異なるフェーズに分かれています。
ソースファイル1ファイルくらいであればまとめて行えますが、規模が大きくなればファイルを分けて「分割コンパイル」を行いますので、明確にフェーズが分かれます。

コンパイルする時には宣言によって関数の情報が分かっていれば十分で、これは #include している <stdio.h> ヘッダや、そこから間接的に #include されるヘッダに含まれています。
コンパイルによってできる「オブジェクトファイル」には、その関数の定義 ( から生成された機械語群 ) はありません。

これが「実行可能なバイナリファイルを作る」時に、別途用意されたコンパイル済みの別ファイルと「リンク」という処理で結合されます。この時は ( 例外もありますが ) リンクするファイルのどこかに関数定義がないとエラーになります。
getchar()putchar()は標準で使われる関数なので、特に意識しなくてもシステムで用意されたファイルと自動的にリンクされて使えますが、使う関数によっては明示的にリンク対象を指示する必要があります。
※例えば数学系の関数の sin(),cos()等は -lm というオプションを指定することによって、libm というモノ ( ライブラリと呼ばれる ) をリンクします。( Linux/UNIX系開発環境の場合 )

投稿2020/06/11 12:21

angel_p_57

総合スコア1681

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

zakonokiwami

2020/06/12 02:04

ご返信頂き、誠にありがとうございます。 お手すきの際にでもご返信頂ければ幸いです。 コンパイルしたものが .exe ではなく、コンパイルしてできた成果物(オブジェクトファイル)に対してリンク処理を行うことで.exe になるとでお間違いないでしょうか。 オブジェクトファイルが .exe ではないとしたら何となるのでしょうか。
angel_p_57

2020/06/12 02:51

> お間違いないでしょうか。 はい。 ただ、1ファイルのソースをコンパイルする位であれば、この「フェーズ」の違いを意識しなくても済む、という話で。 例えば Linux で gcc を使ってアプリをビルドするような場合、フェーズを分けない・分けるで、以下のような手順の違いが出ます。( -c というのが、リンクせずにコンパイルでオブジェクトファイルだけを作るオプション ) * prog.c 1ファイルのコンパイル、コンパイルと同時にシステムで用意するファイルとのリンクを行って実行可能ファイル prog.exe を作る  $ gcc -o prog.exe prog.c * main.c, sub1.c~ のコンパイル、最後に各オブジェクトファイルとシステムで用意するファイルとのリンクを行って、実行可能ファイル prog.exe を作る  $ gcc -o main.o -c main.c  $ gcc -o sub1.o -c sub1.c  $ gcc -o sub2.o -c sub2.c  …  $ gcc -o prog.exe main.o sub1.o sub2.o … > オブジェクトファイルが .exe ではないとしたら何となるのでしょうか。 「オブジェクトファイル」と言う他はないのですが…。 拡張子はLinux/UNIXだと .o にしますね。( 単に名前付けの慣習としての話 ) 実行可能ファイルと何が1番違うかと言うと、中身が機械語命令の塊なのは同じなのですが、「ある関数から別の関数を呼び出す」の部分が未確定になっているところでしょうか。 最終的には「メモリ上のどのアドレスに保存された命令にジャンプするか」が何かしら解決されてないとならなくて、その解決がリンクの担当する重要な仕事です。 オブジェクトファイルは、プログラムとしての完成品の「パーツ」という位置づけにあると言えるでしょう。
angel_p_57

2020/06/12 03:33

少し補足すると、「C言語的には」main の最初から最後まで ( あとそこから呼び出される処理 ) だけ考えれば済む話ですが、実際のプログラムとして実行する場合には、main を呼び出すまでの準備、main 後の後処理等、色々な調整事項があります。 上で「システムで用意するファイルとのリンク」と言っている中には、「準備・後処理まで全部含めた処理の中のパーツとして、ユーザの用意した main を結合する」という意味合いも含まれています。 ※これはC言語そのものの話ではなく、C言語で書いたソースをシステムとしてプログラムにするための、よくある仕組みの話です
guest

0

Q4.宣言と定義について
一般的には定義は実体を伴う、宣言は実体を伴わないと考えれば良いと思います。
C 宣言と定義 | Microsoft Docs

"宣言" では、特定の変数、関数、型、およびその属性の間の関連付けが設定されます。

変数の "定義" では宣言と同じ関連付けが設定されますが、さらに、変数にストレージが割り当てられます。

あるソースに定義があれば、別のソースでその定義を利用する場合は宣言すれば良いだけです。
int x; /定義であり宣言でもある/
extern int x; /宣言のみで別ソースで定義した変数を利用可能/

関数の宣言と定義 | Microsoft Docs

関数プロトタイプは、関数の名前、戻り値の型、および仮パラメーターの型と数を設定します。 関数定義には、関数本体が含まれます。

int func(); /宣言のみで内容がない/
int func(){} /宣言でもあるが定義でもあり内容がある。/

投稿2020/06/11 10:33

rakko_midori

総合スコア4

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

zakonokiwami

2020/06/12 02:07

ご返信頂き、誠にありがとうございます。 変数=宣言、定数=定義だと思っていましたが、違うということ、 とても分かりやすい例まで頂き、より理解が深まりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問