带#的预编译语句

目录

一,条件编译使用分析

二,#error和#line使用分析

三,#pragma使用分析

1,#pragma message

2,#pragma once

3,pragma pack

四,#和##操作符使用分析

1,#操作符

2,##操作符


 

 

 

一,条件编译使用分析

  • 条件编译控制预编译器保留某些代码,删除某些代码。

  • 条件编译的行为类似于C语言中if...else...语句。

条件编译语句:#if...#else...#endif

#include <stdio.h>
​
int main()
{
    const char* s;
​
    #ifdef C     
        s = "This is first printf...\n";
    #else
        s = "This is second printf...\n";
    #endif
​
    printf("%s", s);
​
    return 0;
}

如果定义了宏define C, 则执行if语句。

条件编译本质:

  1. 预编译器根据条件编译指示可以删除保留代码。

  2. 条件编译在预编译期进行分支判断。

插入知识点1:可以通过预编译器命令行定义宏。

gcc -Dmacro = value  file.c

         (宏名称)

或者:

gcc -Dmacro  file.c

(file.c代表编译的文件名)

例如在上面语句中,输出结果为this is second printf...

如果此时我们在预编译系统的命令行加上:gcc -DC file.c

此时输出结果就变为this is first printf...

插入知识点2:#include本质

  1. #include的本质就是将已经存在的文件嵌入到当前文件夹中。

  2. #include的间接包含同样会产生嵌入内容的操作。

例如include<stdio.h>就是把stdio.h包含的代码复制到预处理器中进行处理。

如果调用头文件时,几个头文件都重复包含了某一段代码,那么编译就会产生错误。

解决办法有两个:

1,条件编译:(最常用)

//a.h#includ<stdio.h>#ifndef _A_H   //_A_H命名与头文件对应#define _A_H...#endif;

2,#pragma once

//a.h#pragma once#include<stdio.h>...

注:在工程实际开发中,条件编译也常用来定义产品的发布版和调试版。

二,#error和#line使用分析

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

    用法:

    #error message

    (message不需要双引号)

    同样的,#warning用于生成编译警告,语句和#error一样。

#ifndef _cplusplus  #error this file should be processsed with C++ compiler#endif

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

    用法:

#line unmber "filename"

(filename可以省略)

#line本质是重定义 _LINE_ 和 _FILE_
//test.c
​
#line 1 "qingshan"
​
#include<stdio.h>
int main()
{
    printf("hello world\n")
    return 0;
}

如果没有第三行的代码,编译后就会警告test.c文件的第8行少一个冒号;

有了第三行代码,编译后就会警告qingshan.c文件的第6行少一个冒号;


三,#pragma使用分析

  • #pragma在有些编译器支持,有些编译器不支持

  • #pragma即使在有些编译器中支持,编译器对它的解释也是不一样的。

  • #pragma有很多不同用法,具体功能取决于后面接的parameter

一般用法:#pragma parameter

1,#pragma message

语法:#pragma message("此处为要输出的内容...")

作用:仅仅代表一条编译消息。

2,#pragma once

作用:保证头文件只编译一次。

条件编译可以被所用的编译器支持。

#pragma once的效率高,但只有部分编译器支持。

问:如何保证头文件重复时,编译高效又能被所有编译器支持呢?

答:两者相结合即可。

//a.h
​
#ifndef _A_H
#define _A_H
​
#pragma once
​
  ...
  
#endif

3,pragma pack

不同类型的数据在内存中按照一定的规则排列,而不是一个接一个的排列。

 

类型排列方式不同,两者占用的内存空间不同

 

  • 为什么要内存对齐?

——CPU取内存是分块读取的,块的大小是:1,2,4,8,16...字节

——某些硬件平台只能从规定的相对地址处读取特定类型数据,否则就会产生硬件异常。

  • #pragma pack 则用于内存对齐。

语句:

#pragma pack(1)

...

#pragma pack()

编译器在默认情况下按照4字节对齐,也就是说当

#pragma pack未写时=#pragma pack(4);

#pragma pack(4)struct test1{             //对齐参数  偏移地址  大小    char c1;  //   1        0       1    short s;  //   2        4       2    char c2;  //   1        6       1     int i;    //   4        8       4};#pragma pack()

大小为12

如果加上#pragam pack(1):

1     0     1

1     1     2

1     3     1

1     4     4

大小则变成8。

注意:结构体总长度最后要验证能被对齐参数整除。

四,#和##操作符使用分析

1,#操作符

作用:在预处理器将宏参数转换为字符串。

语句:

#define A(x) #x

printf("%s\n", A(hello world!));

(最后打印结果:hello world!)

2,##操作符

作用:在预处理器连接两个标识符。只在宏定义中有效。

语法:

#define CONNECT(a, b) a##b

int CONNECT(a, 1);     //int a1;

Guess you like

Origin blog.csdn.net/m0_58702068/article/details/118772516