条件编译命令分析:#error 和 #line,#pragma,# 和 ## 操作符使用

举报
CodeAllen 发表于 2021/10/30 00:44:14 2021/10/30
【摘要】 知识来源主要是陈正冲老师的《C语言深度解剖》及Delphi Tang老师的《C语言剖析》,有兴趣的朋友可以看我置顶文章获取   #error 和 #line 使用分析 #error 用于生成一个编译错误消息 用法:          #error message&nb...

知识来源主要是陈正冲老师的《C语言深度解剖》及Delphi Tang老师的《C语言剖析》,有兴趣的朋友可以看我置顶文章获取

 

#error 和 #line 使用分析

#error 用于生成一个编译错误消息

用法:

         #error message       (message不需要使用双引号)

#error 编译指示字用于自定义程序特有编译错误消息

类似的,#warning用于生成编译警告

 

#error 是一种预编译器指示字

#error 可以用于提示编译条件是否满足

 

实验1:#error预处理实验


  
  1. #include <stdio.h>
  2. #ifndef __cplusplus
  3. #error This file should be processed with C++ compiler.
  4. #endif
  5. class CppClass
  6. {
  7. private:
  8. int m_value;
  9. public:
  10. CppClass()
  11. {
  12. }
  13. ~CppClass()
  14. {
  15. }
  16. };
  17. int main()
  18. {
  19. return 0;
  20. }

 

实验2:#error在条件编译中的应用


  
  1. #include <stdio.h>
  2. void f()
  3. {
  4. #if ( PRODUCT == 1 )
  5. printf("This is a low level product!\n");
  6. #elif ( PRODUCT == 2 )
  7. printf("This is a middle level product!\n");
  8. #elif ( PRODUCT == 3 )
  9. printf("This is a high level product!\n");
  10. #endif
  11. }
  12. int main()
  13. {
  14. f();
  15. printf("1. Query Information.\n");
  16. printf("2. Record Information.\n");
  17. printf("3. Delete Information.\n");
  18. #if ( PRODUCT == 1 )
  19. printf("4. Exit.\n");
  20. #elif ( PRODUCT == 2 )
  21. printf("4. High Level Query.\n");
  22. printf("5. Exit.\n");
  23. #elif ( PRODUCT == 3 )
  24. printf("4. High Level Query.\n");
  25. printf("5. Mannul Service.\n");
  26. printf("6. Exit.\n");
  27. #endif
  28. return 0;
  29. }

 

#line的使用

#line用于强制指定新的行号和编译文件名,并对源文件程序的代码重新编译

用法:

  #line number filename

#line 编译指示字的本质是重定义_LINE_ 和_FILE_

 

实验3:#line的使用


  
  1. #include <stdio.h>
  2. // The code section is written by A.
  3. // Begin
  4. #line 1 "a.c"
  5. // End
  6. // The code section is written by B.
  7. // Begin
  8. #line 1 "b.c"
  9. // End
  10. // The code section is written by Delphi.
  11. // Begin
  12. #line 1 "delphi_tang.c"
  13. int main()
  14. {
  15. printf("%s : %d\n", __FILE__, __LINE__);
  16. printf("%s : %d\n", __FILE__, __LINE__);
  17. return 0;
  18. }
  19. // End

小结:

 

 

#pragma 含义:

  • #pragma用于指示编译器完成一些特定的动作
  • #pragma所定义的很多指示字是有编译器特有的
  • #pragma在不同的编译器间是不可以移植的
  1.   预处理器将忽略它不认识的#pragma指令
  2.   不同的编译器可能以不同的方式解释同一条#pragma指令

 

一般用法:#pragma parameter     (不同的parameter参数语法和意义各不相同)

 

#pragma message

  • message 参数在大多数编译器中都有类似的实现
  • message参数在编译时输出消息到编译输出窗口中
  • message 用于条件编译中可提示代码的版本信息

  
  1. #if defined(ANDROID20)
  2. #pragma message("Compile Android SDK 2.0 ...")
  3. #define VERSION "Android 2.0"
  4. #endif
  5. #error 和#warning 不同,#pragma message 仅仅代表一条编译信息,不代表程序错误

实验1 #pragma message使用分析


  
  1. #include <stdio.h>
  2. #if defined(ANDROID20)
  3. #pragma message("Compile Android SDK 2.0...")
  4. #define VERSION "Android 2.0"
  5. #elif defined(ANDROID23)
  6. #pragma message("Compile Android SDK 2.3...")
  7. #define VERSION "Android 2.3"
  8. #elif defined(ANDROID40)
  9. #pragma message("Compile Android SDK 4.0...")
  10. #define VERSION "Android 4.0"
  11. #else
  12. #error Compile Version is not provided!
  13. #endif
  14. int main()
  15. {
  16. printf("%s\n", VERSION);
  17. return 0;
  18. }

  
  1. #pragma once
  2. int g_value = 1;

 

#pragma once

  • #pragma once用于保证头文件只被编译一次
  • #pragma once是编译器相关的,不一定被编译

 

实验2:#pragma once使用


  
  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "global.h"
  4. int main()
  5. {
  6. printf("g_value = %d\n", g_value);
  7. return 0;
  8. }

 

#pragma pack

内存对齐:不同类型的数据在内存中按照一定的规则排列  ,而不一定是顺序的一个个的排序

 

举个例子:

在内存中存储方式如图:

 

为什么 需要内存对齐?

  • CPU对内存的读取不是连续的,而是分块读取的,块的大小只能是1,2,4,8,16 。。。字节
  • 当读取操作的数据未对齐,则需要两次总线周期来访问内存,因此性能会大打折扣
  • 某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则则产生硬件异常

#pragma pack 用于指定内存对齐方式

 

 

#pragma pack 能够改变编译器的默认对齐方式

 

struct占用的内存大小

  • 第一个 成员起始于0偏移处
  • 每个成员按其类型大小和pack参数中较小的一个进行对齐
  1.     偏移地址必须能被对齐参数整除
  2.     结构体成员的带下取其内部长度最大的数据成员作为其大小
  • 结构退总长度必须为所有对齐参数的整数倍

编辑器在默认状态下按照4字节对齐

 

实验3:结构体大小计算


  
  1. #include <stdio.h>
  2. #pragma pack(2)
  3. struct Test1
  4. {
  5. char c1;
  6. short s;
  7. char c2;
  8. int i;
  9. };
  10. #pragma pack()
  11. #pragma pack(4)
  12. struct Test2
  13. {
  14. char c1;
  15. char c2;
  16. short s;
  17. int i;
  18. };
  19. #pragma pack()
  20. int main()
  21. {
  22. printf("sizeof(Test1) = %d\n", sizeof(struct Test1));
  23. printf("sizeof(Test2) = %d\n", sizeof(struct Test2));
  24. return 0;
  25. }

 

实验4:


  
  1. #include <stdio.h>
  2. #pragma pack(8)
  3. struct S1
  4. {
  5. short a;
  6. long b;
  7. };
  8. struct S2
  9. {
  10. char c;
  11. struct S1 d;
  12. double e;
  13. };
  14. #pragma pack()
  15. int main()
  16. {
  17. printf("%d\n", sizeof(struct S1));
  18. printf("%d\n", sizeof(struct S2));
  19. return 0;
  20. }

小结:

 

 

# 和 ## 操作符使用

#运算符用于预处理期将宏参数转换为字符串

#的转换作用是在预处理期完成的,因此只在宏定义中有效

编译器不知道#的转换作用

用法:


  
  1.   #define STRING(x) #x
  2. printf("%s\n",STRING(Hello World!));

实验1:#运算符的基本用法


  
  1. #include <stdio.h>
  2. #define STRING(x) #x
  3. int main()
  4. {
  5. printf("%s\n", STRING(Hello world!));
  6. printf("%s\n", STRING(100));
  7. printf("%s\n", STRING(while));
  8. printf("%s\n", STRING(return));
  9. return 0;
  10. }

 

实验2:#运算符的妙用


  
  1. #include <stdio.h>
  2. #define CALL(f, p) (printf("Call function %s\n", #f), f(p))
  3. int square(int n)
  4. {
  5. return n * n;
  6. }
  7. int func(int x)
  8. {
  9. return x;
  10. }
  11. int main()
  12. {
  13. int result = 0;
  14. result = CALL(square, 4);
  15. printf("result = %d\n", result);
  16. result = CALL(func, 10);
  17. printf("result = %d\n", result);
  18. return 0;
  19. }

 

##运算符用于在预处理期粘连两个标识符

##的连接作用是字预处理期完成的,因此只在宏定义中有效

编译器不知道##的连接作用

用法:


  
  1. #define CONNECT(a,b) a##b
  2. int CONNECT(a,1); //int a1;
  3. a1 = 2;

 

实例3:##运算符的基本用法


  
  1. #include <stdio.h>
  2. #define NAME(n) name##n
  3. int main()
  4. {
  5. int NAME(1);
  6. int NAME(2);
  7. NAME(1) = 1;
  8. NAME(2) = 2;
  9. printf("%d\n", NAME(1));
  10. printf("%d\n", NAME(2));
  11. return 0;
  12. }

 

实例4:##运算符的工程应用


  
  1. #include <stdio.h>
  2. #define STRUCT(type) typedef struct _tag_##type type;\
  3. struct _tag_##type
  4. STRUCT(Student)
  5. {
  6. char* name;
  7. int id;
  8. };
  9. int main()
  10. {
  11. Student s1;
  12. Student s2;
  13. s1.name = "s1";
  14. s1.id = 0;
  15. s2.name = "s2";
  16. s2.id = 1;
  17. printf("s1.name = %s\n", s1.name);
  18. printf("s1.id = %d\n", s1.id);
  19. printf("s2.name = %s\n", s2.name);
  20. printf("s2.id = %d\n", s2.id);
  21. return 0;
  22. }

小结:

 

文章来源: allen5g.blog.csdn.net,作者:CodeAllen的博客,版权归原作者所有,如需转载,请联系作者。

原文链接:allen5g.blog.csdn.net/article/details/89064814

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。