C语言预处理指令大全

C语言预处理指令

文章目录

  • C语言预处理指令
    • define
      • 语法
      • Linux编译时指定宏的值及宏
      • 删除已有的宏
      • C语言允许多参数的宏及宏函数
        • 宏函数需要注意的事项
        • 参数宏创建字符串
        • 预处理粘合剂
    • line
    • warning
    • error
    • pragma
    • 条件编译
      • 语法格式
      • 头文件卫士

  • C语言中带#的为预处理指令
  • Linux中 (gcc -E xxx.c) 进行预处理
  • Linux中(gcc -D 宏 = 值 xxx.c)定义宏

define

#define MACRO_NAME CONTENT
//MACRO_NAME 宏名称 一般用于大写 区别于变量
//CONTENT 要替换的内容  可以是常量 变量 表达式 语句

#define MACRO_NAME //也可以只定义宏 不加替换的东西

语法

  • #前后可以有空格
  • 宏名称不能有空格 会把define后面第一个标识符当作宏名称 宏名称后面的内容当作要替换的内容
#define T X Z
T;//T会被替换成 X Z
  • 宏定义只是简单的替换
  • 宏定义如果需要拆行需要\
  • 宏定义不是说明或语句,不需要分号作为结束标识 如果在宏定义有;也会视为替换内容的一部分。
  • 预处理其实就是宏展开的一部分。
  • 宏定义允许嵌套,在展开时不会凭空添加()简单层层替换而已。
#define MULTI1(a,b) ((a)*(b))  //必须每个地方都加上括号 

//otherwise

#define MULTI2(a,b) (a*b)
int a=2,b=3;
int c = MULTI1(a+1,b+2);
int d = MULTI2(a+1,b+2);

printf("c = %d\n",c); // a+1*b+2
printf("d = %d\n",d); // (a+1)*(b+2)

/*
值得注意的时,define是字符内容的直接替换。
*/
  • define与typedef区别

    define直接替换,然而typedef是别名

    下面一个例子你就懂了

#define IT int *
typedef int *TT;

int main(){
    IT a,b;// int *a,b;     //b不是int*类型而是int类型
    TT m,n;// int *m,*n;
    
    unsigned IT x; //allow
    unsigned TT y; //compile error
    return 0;
}
  • define与const区别

    #define定义的常量称为明示常量

    const定义的常量一般表示只读,其实不是真正的常量

    同样举个栗子

#define DN 10
const int CN = 20;

static int arr[DN];
static int brr[CN];// compile error
int crr[CN]; // compile error  在全局区无法确定数组大小,全局区严格控制内存大小,不允许变长。
const int ci = DN*20;
const int cc = CN*20;
int main(){
    int drr[CN];//stack区 在栈区允许边长数组
    static int err[CN];  //一样也是全局区
    static int frr[CN];   //真正的常量是可以的
    return 0;
}

Linux编译时指定宏的值及宏

  • gcc -D 宏 = 值 xxx.c

删除已有的宏

  • #undef

C语言允许多参数的宏及宏函数

#define MACRO_NAME(ARGLIST) CONTENT
//MACRO_NAME 宏名称
//ARGLIST 宏参数列表   不需要类型,只需要标识符即可,多个参数用逗号隔开, 支持...(多参数)
//CONTENT   //宏所需要替换的语句内容
  • 宏函数需要注意的事项

    • 宏函数名和()之间不能存在空格,不然在空格前面的部分就会被认定为宏名称。
    • 带参数的宏不会为形参分配内存空间,因此不必指明参数的类型
    • 宏函数的参数允许类型 va_arg(ap,type)
#define T(type,b) type c = b

int main(){
    T(int,10); //int c = 10;
    return 0;
}
  • 参数宏创建字符串

#define STR(arg) #arg

int main(){
    printf("第一个C语言程序:"STR(Hello world!));
    return 0;
}
  • 预处理粘合剂

    • 可以看我之前的内容里面有详细的案例(在此就不赘述了)

line

  • #line n filename 指定行号

warning

  • 让预处理(编译)产生警告 #warning

error

  • #error 让预处理(编译)产生错误 直接中断编译

pragma

  • 在预处理阶段会被保留下来,用于设置编译器属性
#pragma GCC dependency <文件> / "文件"     //表示当前文件依赖于 ""/<> 中文件     如果 ""/<>中文件比当前文件更新,则编译会报警告   依赖: 如果一个文件依赖于另外一个文件,文件新旧:更新的文件意味着修改
#pragma GCC poison 标识                   //对标识进行投毒     标识将无法在代码中使用
#pragma pack(n)                          //n取1,2,4,8     改变对齐补齐默认字节

条件编译

  • 在预处理时,会根据条件进行选择性的编译代码 (只有一部分代码会被编译)
  • 与分支语句不同,分支(if switch)会把所有分支都编译到代码中,不管分支有没有执行
  • 条件编译,只会选择其一个分支进行编译,所以生成的执行文件会比较小 运行效率比较高
  • 分支语句,会把所有分支进行编译到可执行文件中,执行文件比较大,在运行时进行判断执行具体分支

语法格式

  • #ifdef && #ifndef #else #endif
#ifdef MACRO_NAME
	//有定义运行,被编译
#endif

#ifndef MACRO_NAME
	//没定义运行
#else
	//有定义
#endif
  • #if #elif
选择其一其他预处理时删除。
#if(条件1)
    
#elif(条件2)
    
#else
    
#endif

头文件卫士

  • 所有C语言头文件都应该置于头文件卫士中。
#ifndef MACRO_H__ //如果未定义 进行定义  防止多次定义读取
#define MACRO_H__

#endif  //MACRO_H__
  • 第一次在程序中导入该头文件时,MACRO_H__宏是没有定义过的,所以第一次会把头文件中的内容导入到代码中,当后面再#include该头文件时,则发现宏已经被定义过了,所以不会再导入头文件的内容
  • 作用: 防止头文件的内容重复导入 重复导入可能引发重定义的错误

你可能感兴趣的:(Linux,C语言,c语言,linux,开发语言)