プリプロセスを追う (関数の宣言)
.i ファイルの中ではどこで関数の宣言が行われているのでしょうか?
ConsoleApplication1.cpp の中にある、
#include <stdio.h>
#include "MySource.h"
int myFunc();
int main()
{
printf("Hello World!\n");
printf("myFunc: %d\n", myFunc());
printf("mySourceFunc: %d\n", mySourceFunc());
printf("mySourceFunc1: %d\n", mySourceFunc1(20));
printf("mySourceFunc2: %d\n", mySourceFunc2(1,30));
}
int myFunc()
{
return 123;
}
に当たる部分を .i ファイルから探してみます。
手順
.i ファイルを開きます
[ソリューション エクスプローラー] よりプロジェクト項目を右クリック、[エクスプローラーでフォルダーを開く] を押下します
"Debug" フォルダを開きます
"ConsoleApplication.i" をテキストエディタで開きます
今回探したいのは #include "MySource.h"
部分でした。
ですから、テキストエディタの検索機能で "MySource.h" などと検索します
私の環境では ConsoleApplication.i の 10698 行目に該当語句がありました
また、.i ファイルの終端が 10720 行目であったことも確認できました
.i ファイルから重要箇所をこちらに抜粋します
#line 1 "D:\\User\\Desktop\\ConsoleApplication1\\ConsoleApplication1\\MySource.h"
#pragma once
int mySourceFunc();
int mySourceFunc1(int);
int mySourceFunc2(int, int);
#line 3 "D:\\User\\Desktop\\ConsoleApplication1\\ConsoleApplication1\\ConsoleApplication1.cpp"
int myFunc();
int main()
{
printf("Hello World!\n");
printf("myFunc: %d\n", myFunc());
printf("mySourceFunc: %d\n", mySourceFunc());
printf("mySourceFunc1: %d\n", mySourceFunc1(20));
printf("mySourceFunc2: %d\n", mySourceFunc2(1,30));
}
int myFunc()
{
return 123;
}
今見えているテキストがソースファイル (.c) をプリプロセス処理したものです。また、#include 処理の実態です。基本的には指定したテキストファイルの中身を展開しているに過ぎません。("#line" 行はコメントです)
こちらの前半部分で、mySourceFunc 関数の宣言を
#include <stdio.h>
int myFunc();
int mySourceFunc();
int mySourceFunc1(int);
int mySourceFunc2(int, int);
int main()
{
printf("Hello World!\n");
printf("myFunc: %d\n", myFunc());
printf("mySourceFunc: %d\n", mySourceFunc());
printf("mySourceFunc1: %d\n", mySourceFunc1(20));
printf("mySourceFunc2: %d\n", mySourceFunc2(1,30));
}
int myFunc()
{
return 123;
}
というように、include を使用せずに行っておりました。プリプロセス処理後である .i ファイルと比べてみると、同じような形になっていることがよくわかると思います。
プリプロセスでは数多くのヘッダーファイル (.h) がソースファイル (.c/.cpp) に取り込まれ、一見ややこしいのですが、プリプロセス後には一つのテキストファイル (.i) になるのだ、ということが見て取れると思います。
printf の宣言箇所
.i ファイルですが、ファイルの大部分 (空行込みで10000行近く) が、たった一行、#include <stdio.h>
に起因することに気づかれましたか。標準 C ライブラリのヘッダファイルです。これらすべての説明は私にはしきれませんし、できません。
しかし、使用している関数の宣言くらいは確認してみます。
いまのサンプルソースでは printf 関数を使用しています。printf 関数は stdio.h で宣言されている関数です。では "ConsoleApplication.i" に宣言箇所があるはずです。
"ConsoleApplication.i" をテキストエディタで開きます。
"printf" で検索します。
私の環境では 9237 行目の下記の箇所が該当しました :
#line 948 "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22000.0\\ucrt\\stdio.h"
__inline int __cdecl printf(
char const* const _Format,
...)
ヘッダーファイルも確認します。
Visual Studio で ConsoleApplication1.cpp を開きます
printf の呼び出し箇所で F12 を押下します
次の箇所が表示されました
これを見るに Windows の開発環境における printf はインライン関数として記載されており、ヘッダファイルに実装があったのですね。実際の処理は _vfprintf_l で (さらに辿ると __stdio_common_vfprintf で) 行うようです。(私はこれを書いている今初めて知りました)
このページはここで終わります。このページでは下記を行いました。
- .i ファイル内を確認し、自作関数 mySourceFunc が宣言される箇所を確認した
- .i ファイル内を確認し、C 標準ライブラリの printf が宣言/実装される箇所を確認した
ところで、.i ファイルとヘッダでは表示されている文字列が少し異なります
.i ファイル | __inline int __cdecl printf
|
---|
ヘッダファイル | _Check_return_opt_ _CRT_STDIO_INLINE int __CRTDECL printf
|
---|
それは、ヘッダファイル側はマクロで書かれているためです。マクロについては次のページで説明します。