第23课 - #error 和 #line 使用分析
第23课 - #error 和 #line 使用分析
1. #error 的用法
(1)#error 是一个预处理器指示字,用于生成一个编译错误消息,这个消息最终会传递到编译器(gcc)
在思考这一点的过程中,领悟到了两个点:
① 使用 gcc 编译代码,输出的错误(警告)信息,是由预处理器、编译器、汇编器、链接器产生的。
② gcc表示整个编译过程,它会调用 预处理器程序 -> 编译器程序 -> 汇编器程序 -> 链接器程序
(2)使用方法:#error message // 不需要在message上使用双引号
(3)#error 编译指示字用于自定义程序员特有的编译错误消息。类似的,#warning 用于生成编译警告错误
(4)#error 可用于提示编译条件是否满足。编译过程中的任何错误意味着无法生成最终的可执行程序。
下面我们通过一个示例程序来说明 #error 的用法:
下面是一段C++ 的代码,如果我们错误的使用gcc对其进行编译就会报错
1 #include <stdio.h> 2 3 class CppClass 4 { 5 private: 6 int m_nValue; 7 public: 8 CppClass(){}; 9 ~CppClass(){}; 10 }; 11 12 int main() 13 { 14 return 0; 15 }
使用gcc编译该代码报错
那如何解决这个问题呢?答案就是使用 条件编译 + #error
1 #include <stdio.h> 2 3 // __cplusplus宏是C++编译器内置的一个宏,C编译器中是没有的 4 // 如果使用C编译器编译该程序#error就会报编译报错 5 #ifndef __cplusplus 6 #error This file should be processed with C++ compiler 7 #endif 8 9 class CppClass 10 { 11 private: 12 int m_nValue; 13 public: 14 CppClass(){}; 15 ~CppClass(){}; 16 }; 17 18 int main() 19 { 20 return 0; 21 }
在上篇文章的最后,我们分析了一个通过条件编译区分产品版本的小程序,在那个代码中我们没有考虑一种情况,那就是如果没有定义PRODUCT这个宏会怎么样?
#include <stdio.h> void f() { #if (PRODUCT == 1) printf("This is a low level product!\n"); #elif (PROUDCT == 2) printf("This is a middle level product!\n"); #elif (PRODUCT == 3) printf("This is a high level product!\n"); #endif } int main() { f(); printf("1. Query Information.\n"); printf("2. Record Information.\n"); printf("3. Delete Information.\n"); #if (PRODUCT == 1) printf("4. Exit.\n"); #elif (PRODUCT == 2) printf("4. High Level Query.\n"); printf("5. Exit.\n"); #elif (PRODUCT == 3) printf("4. High Level Query.\n"); printf("5. Mannual Service.\n"); printf("6. Exit.\n"); #endif return 0; }
如果我们在编译该程序时没有通过-DPRODUCT指定这个宏的值,编译并不会报错但是执行结果就有问题了。
使用 #error 完善该程序,如果没有定义PRODUCT或者PRODUCT的值不为1、2、3中的一个,程序在编译时就会报错。
1 #include <stdio.h> 2 3 void f() 4 { 5 #if (PRODUCT == 1) 6 printf("This is a low level product!\n"); 7 #elif (PROUDCT == 2) 8 printf("This is a middle level product!\n"); 9 #elif (PRODUCT == 3) 10 printf("This is a high level product!\n"); 11 #else 12 // 如果PRODUCT未定义或定义了但!=1 != 2 != 3 13 #error The PRODUCT macro is NOT defined! 14 #endif 15 } 16 17 int main() 18 { 19 f(); 20 21 printf("1. Query Information.\n"); 22 printf("2. Record Information.\n"); 23 printf("3. Delete Information.\n"); 24 25 #if (PRODUCT == 1) 26 printf("4. Exit.\n"); 27 #elif (PRODUCT == 2) 28 printf("4. High Level Query.\n"); 29 printf("5. Exit.\n"); 30 #elif (PRODUCT == 3) 31 printf("4. High Level Query.\n"); 32 printf("5. Mannual Service.\n"); 33 printf("6. Exit.\n"); 34 #else 35 // 如果PRODUCT未定义或定义了但!=1 != 2 != 3 36 #error The PRODUCT macro is NOT defined! 37 #endif 38 39 return 0; 40 }
2. #line 的用法
(1)#line 用于强制指定新的行号和编译文件名,并对源程序的代码重新编号
(2)用法:
① #line number newFilename
② #line number // 不改变文件名,只改变行号
(3)#line 编译指示字的本质是重定义 __LINE__ 和 __FILE__
1 #include <stdio.h> 2 3 int main() 4 { 5 printf("%s : %d\n", __FILE__, __LINE__); 6 7 #line 1 "new_line.c" // 这里改变了行号和文件名,行号为1(下一行行号为1)、文件名为new_line.c(注意这里需要使用用双引号) 8 9 printf("%s : %d\n", __FILE__, __LINE__); 10 11 return 0; 12 }
// 输出结果
swj@ubuntu:~/c_course/ch_23$ ./a.out
line.c : 5
new_line.c : 2
#line 是C语言早期的产物(在当今的软件工程中已经不使用了),那时候代码量比较小,通常放到一个文件中。如果这个程序由几个人分工协作完成的话,就是每个人先各写各的,最后再统一放到一个文件中。
那如果编译发生错误,如何知道错误的代码是谁写的呢?这个就要使用 #line 预处理指令了。
1 #include <stdio.h> 2 3 // The code section is written by A. 4 // Begin 5 #line 1 "a.c" 6 7 // End 8 9 // The code section is written by B. 10 // Begin 11 #line 1 "b.c" 12 13 // End 14 15 // The code section is written by Scott. 16 // Begin 17 #line 1 "scott_shi.c" 18 19 20 int main() 21 { 22 printf("%s : %d\n", __FILE__, __LINE__); 23 24 printf("%s : %d\n", __FILE__, __LINE__) // 这里编译会报错 25 26 return 0; 27 } 28 29 // End
编译报错,提示是 scott_shi.c 这个文件的 第9行 发生错误,这样就定位了是哪个人写的。