事前定義マクロとプラグマ 解答ページ | Programming Place Plus C言語編 第29章
Programming Place Plus トップページ – C言語編 – 第29章
問題① プログラムの実行直後に、そのソースファイルをコンパイルしたときの日付・時刻を出力してみてください。
たとえば、次のようになります。
#include <stdio.h>
int main(void)
{
( "BuildTime: %s %s\n", __DATE__, __TIME__ );
printf
( "適当なプログラム" );
puts}
実行結果:
BuildTime: Sep 20 2009 16:12:26
適当なプログラム
日付と時刻を、プログラムの実行時に判断しているわけではないことがポイントです。__DATE__ も __TIME__ も、プリプロセスで処理されているので、ビルドが終わった時点では確定済みです。そのため、実行するたびに結果が変わるようなことはありません。
問題② ソースコード上のある地点で、ソースファイルの名前と行数を出力できるデバッグ関数を次のように作成しました。 しかし、この関数には実用上の問題があります。問題点を指摘してください。
void printLog()
{
( "File: %s Line: %d\n", __FILE__, __LINE__ );
printf}
実用上の問題を想像できるでしょうか? 実際に使ってみるとよく分かります。
#include <stdio.h>
void printLog();
int main(void)
{
( "aaaaa" );
puts();
printLog( "bbbbb" );
puts();
printLog( "ccccc" );
puts}
void printLog()
{
( "File: %s Line: %d\n", __FILE__, __LINE__ );
printf}
実行結果:
aaaaa
File: c:\main.c Line: 18
bbbbb
File: c:\main.c Line: 18
ccccc
__FILE__ や __LINE__ は、その記述がある場所のファイル名と行数に置換されるので、 printLog関数のように関数化してしまうと、printLog関数の内側の行数にしかなりません。 実用上、本当に出力して欲しい情報は、printLog関数を呼び出した位置の行数のはずですから、これでは問題があります。
解決策は、関数にするのをやめて、関数形式マクロで実装することです。
#include <stdio.h>
#define PRINT_LOG() printf( "File: %s Line: %d\n", __FILE__, __LINE__ );
int main(void)
{
( "aaaaa" );
puts();
PRINT_LOG( "bbbbb" );
puts();
PRINT_LOG( "ccccc" );
puts}
実行結果:
aaaaa
File: c:\main.c Line: 8
bbbbb
File: c:\main.c Line: 10
ccccc
これなら、PRINT_LOGマクロが展開された位置に __FILE__ と __LINE__ も置かれるので、呼び出した場所のファイル名と行数が出力できます。
問題③ 自分の使っているコンパイラに用意されている pragma指令について調べてください。
解答は環境によるので明確には書きません。この問題の本当の意図は、自分で必要な情報を調べる方法を身に付けて欲しいという点にあります。少なくとも、自分の使っているコンパイラのドキュメントの場所や、その読み方は身に付けましょう。
情報の信憑性の問題もありますから、原則的に、コンパイラを作ったメーカーの公式ドキュメントを参照するべきです。公式ドキュメントに書かれていることが難しくて理解できないときに、分かりやすく説明し直している情報を探すのが適切な流れです。いずれにしても、コンパイラの種類やバージョン、書かれた時期などをきちんと確認するようにしてください。
return 0;
を削除(C言語編全体でのコードの統一)’2018/3/5 全面的に文章を見直し、修正を行った。
’2009/9/20 新規作成。
Programming Place Plus のトップページへ