在前文中,我们曾看到,预处理指令的先执行性受到了原生字符串字面量的挑战。那么,这一指令的不符直觉之处还有哪些呢?这一次,峰子得寸进尺,进一步对 #include 指令进行战略试探。
首先,若将文件以词法记号为单位进行分割,存入多文件中,再向同一文件中做 #include ,会发生什么呢?
//test.cpp
#include "include.txt"
#include "using.txt"
#include "outerfunc.txt"
#include "mainfuncbegin.txt"
#include "mainfunc.txt"
#include "mainfuncend.txt"
//include.txt
#include <iostream>
//using.txt
using namespace std;
//outerfunc.txt
void outerfunc()
{
cout << "From outerfunc():" <<endl;
}
//mainfuncbegin.txt
int main(int argc,char * argv[])
{
//mainfunc.txt
cout << argv[0] << endl;
outerfunc();
//mainfuncend.txt
}
编译环境:TDM-GCC-32 4.7.2,Windows 7 旗舰版。
编译选项:
mingw32-g++ test.cpp -o test.exe -std=c++11
mingw32-g++ test.cpp -o test.exe
这个文件的编译是成功的。
运行结果:
prompt> dir /d
......
[.] mainfunc.txt outerfunc.txt using.txt
[..] mainfuncbegin.txt test.cpp
include.txt mainfuncend.txt test.exe
8 个文件 1,002,239 字节
2 个目录 9,725,964,288 可用字节
prompt> test
test
From outerfunc():
看起来,这样的分割是可以为编译器所接受的。
但是,是不是把文件无论怎么分割,都可以轻松通过编译呢?
//test.cpp
#include "markstart.txt"
#include "others.txt"
#include "markend.txt"
int main(){ return 0; }
//markstart.txt
R"(
//others.txt
Hello, world!
//markend.txt
)"
编译环境:Windows 7 旗舰版,TDM-GCC-32 4.7.2编译选项和结果:
prompt> dir /d
......
[.] markend.txt others.txt test.cpp
[..] markstart.txt
4 个文件 116 字节
2 个目录 9,725,747,200 可用字节
prompt> mingw32-g++ test.cpp -o test.cpp -std=c++11
In file included from test.cpp:1:0:
markstart.txt:1:1: error: unterminated raw string
R"(
^
编译失败。
结合上个实验的结论不难明白,R"( 之后的内容都视为纯的字符串,不发挥语法功能,直到遇到 )" 为止。但是显然,它并不知道何时遇到或会不会遇到一个截止符,如果后面发现了新的 #include 指令,到底要不要展开,所以,编译器不可能允许上述代码通过编译。
峰子的一系列后续实验都指向这个结论:程序可以被分成多文件结构,当并且只有当每个文件中包含了完整的一个个词法单元(或称词法记号)时。