はじめに
私は初心者である。この備忘録を参考にされようとしている他の初心者の方は、ここに書かれていることを鵜呑みになさらぬようお願いしたい。何か間違いを見つけた方はコメント欄でご報告頂きたい。
前処理
C言語のソースファイルをコンパイルするとき、コンパイラはまず前処理をしてから機械語へ翻訳する。
前処理では次のような処理が行われる。
- マクロの定義と置換
- ファイルの取り込み
- 条件付きコンパイル
- その他、行の連結、処理系特有の動作、わざとエラーを起こすなど
とのことだ。これから見ていこう。
#include <stdio.h>
のように先頭に#
のある行は前処理に対する命令だ。それらを前処理指令というらしい。前処理は基本的に行を単位として行われる。
行の連結
前処理指令の行が長くて、2行以上にまたがって書きたいときは行の連結を指示する。
行末にバックスラッシュ\
を書くと改行文字がないことになる。
マクロとは
前処理には指定した文字列を置き換える機能がある。その文字列をマクロという。
マクロ名は大文字で始める慣習がある。
マクロの定義と展開
マクロは#define
指令で定義する。
#define AdultAge 20
AdultAge
がマクロで、その後に続く部分をマクロ本体という。
このように定義すると、それ以降そのソースファイルに出てくるAdultAge
という語がマクロ本体の20に置き換えられる。
if (age >= AdultAge)
引数付きマクロ
#define Square(x) x * x
このようにするとマクロが展開された時に、マクロ本体の仮引数のところに実引数として指定された語の並びが入る。
他にも色々使用例が書いてある。私の先入観的には前処理はプログラムやファイルに関わる設定をするための場所だと思ってるから、なんか汚いコードに見えてしまうけど。実際使うのかなー。
マクロと列挙定数
マクロと列挙定数なんて欄もあるが、必要感じないから飛ばす。
必要になったら後日追記する。
処理系によって定義されているマクロ
いくらかのマクロは処理系によって定義されている。主なものは以下
-
__FILE__
このファイルの名前 -
__DATE__
前処理の日付を表す文字列 -
__TIME__
前処理の時刻を表す文字列 -
__LINE__
現在の行番号 -
__STDC__
C言語の規格に準拠した処理系かどうか -
__STDC_VERSION__
準拠しているC言語の規格を表す整数
変数名と同様にアンダースコアで始まるマクロは定義すべきでない。
#include <stdio.h>
int main(void){
printf("file: %s\n", __FILE__);
printf("date: %s\n", __DATE__);
printf("time: %s\n", __TIME__);
printf("line: %d\n", __LINE__);
return 0;
}
出力は以下
file: hello.c
date: Feb 22 2023
time: 20:55:40
line: 7
ファイルの取り込み
#include
によるファイルの取り込み
#include
指令は、指定したファイルの中身をその行の位置に取り込む。
#include <stdio.h> // stdio.hという名のファイルを取り込む
ファイル名が<>
で囲まれていると、処理系が提供しているファイル群からその名前のファイルを探す。
ファイル名が""
で囲まれていると、現在のディレクトリからその名前のファイルを探す。
#include "myheader.h"
追記 上記は書籍からの内容だが、このようなコメントも頂いた。
ヘッダファイルの書き方
複数のソースファイルでプログラムを作る場合には、ファイル間で共通の宣言などを入れた~.h
というヘッダファイルを作り、それをそれぞれの~.c
というソースファイルで取り込むと便利だ。
ヘッダファイルの使い方は前処理指令と、外部変数や関数などの宣言だけを書くのが一般的だ。
それ以外にも列挙型などの型に関する宣言や内部的インライン関数の宣言と定義もよく入れるそうだ。
これら諸々のことを復習するための演習が書籍には記載されているのだが、残念なことにこの書籍は演習の答えが載ってない。
演習では、
計4人の点数を二人ずつ比べ、それぞれ点数の高い方を出力。その二人のうちで、さらに高い点数のものを勝者とする。
というプログラムをmain
、関数用、ヘッダファイルでファイルを分けて書くことになっている。
エラーもなく出力できたが、私のコードの書き方で誤っている部分や修正を加えるべきものを見つけた方は教えていただけると助かる。
#include <stdio.h>
#include "winner.h"
int main(void){
int w1, w2, champ;
debug = 1;
w1 = winner1(75, 78);
w2 = winner2(81, 68);
champ = max(w1, w2);
printf("Gold Medal %d\n", champ);
return 0;
}
#include <stdio.h>
#include "winner.h"
int winner1(int x, int y){
int z;
if(debug)
printf("winner1: %d vs %d\n", x, y);
z = max(x, y);
printf("%d wins\n", z);
return z;
}
#include <stdio.h>
#include "winner.h"
int winner2(int x, int y){
int z;
if(debug)
printf("winner2: %d vs %d\n", x, y);
z = max(x,y);
printf("%d wins\n", z);
return z;
}
#include <stdio.h>
extern int debug;
int debug;
static inline int max(int, int);
int winner1(int, int);
int winner2(int, int);
static inline int max(int x, int y){
if(debug)
printf("comparing %d and %d\n", x, y);
return (x > y)? x:y;
}
出力は以下
winner1: 75 vs 78
comparing 75 and 78
78 wins
winner2: 81 vs 68
comparing 81 and 68
81 wins
comparing 78 and 81
Gold Medal 81
コメントでextern
宣言はヘッダファイルに書いても変数宣言(int debug;
)は書かない方が良いと教えていただいた。各々のファイルで宣言してやり直したら、それもちゃんと動いた。
今回の内容は富永和人氏の新しいC言語の教科書を参考に書き留めてます。