C语言预处理命令(kk-zkx)

以#号开头的命令称为预处理命令。

编译是针对单个源文件的,一次编译操作只能编译一个源文件,如果程序中有多个源文件,就需要多次编译操作。

链接(Link)是针对多个文件的,它会将编译生成的多个目标文件以及系统中的库、组件等合并成一个可执行程序。

这些在编译之前对源文件进行简单加工的过程,就称为预处理(即预先处理、提前处理)。

预处理主要是处理以#开头的命令,例如#include <stdio.h>等。预处理命令要放在所有函数之外,而且一般都放在源文件的前面。

预处理是C语言的一个重要功能,由预处理程序完成。当对一个源文件进行编译时,系统将自动调用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。

编译器会将预处理的结果保存到和源文件同名的.i文件中,例如 main.c 的预处理结果在 main.i 中。和.c一样,.i也是文本文件,可以用编辑器打开直接查看内容。

C语言提供了多种预处理功能,如宏定义、文件包含、条件编译等,合理地使用它们会使编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。

栗子

// 栗子1

#include<stdio.h>

//不同平台,引入不同的头文件
#if _WIN32
#include<windows.h>
#elif _linux_
#include<unistd.h>
#endif

int main()
{
    //不同平台下调用不同的函数
    #if _WIN32
    Sleep(5000);
    #elif _linux_
    sleep(5);
    #endif

    puts("hello world!\n");

    return 0;
}

#include叫做文件包含命令,用来引入对应的头文件(.h文件)。

使用尖括号< >和双引号" "的区别在于头文件的搜索路径不同:

  • 使用尖括号< >,编译器会到系统路径下查找头文件;
  • 而使用双引号" ",编译器首先在当前目录下查找头文件,如果没有找到,再到系统路径下查找。
    也就是说,使用双引号比使用尖括号多了一个查找路径

「在头文件中定义定义函数和全局变量」这种认知是原则性的错误!不管是标准头文件,还是自定义头文件,都只能包含变量和函数的声明,不能包含定义,否则在多次引入时会引起重复定义错误。

宏定义

#define 叫做宏定义命令,它也是C语言预处理命令的一种。所谓宏定义,就是用一个标识符来表示一个字符串,如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。

//宏定义的一般形式为:
#define  宏名  字符串
//#表示这是一条预处理命令,所有的预处理命令都以 # 开头。宏名是标识符的一种,命名规则和变量相同。
//字符串可以是数字、表达式、if 语句、函数等。
//这里所说的字符串是一般意义上的字符序列,不要和C语言中的字符串等同,它不需要双引号。
//程序中反复使用的表达式就可以使用宏定义,例如:
#define M (n*n+3*n)

需要注意的是,在宏定义中表达式(nn+3n)两边的括号不能少,否则在宏展开以后可能会产生歧义。

对 #define 用法的几点说明

  • 宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单粗暴的替换。字符串中可以含任何字符,它可以是常数、表达式、if 语句、函数等,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的源程序时发现。
  • 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起替换。
  • 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。
  • 代码中的宏名如果被引号包围,那么预处理程序不对其作宏代替
  • 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换。
  • 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母。
  • 可用宏定义表示数据类型,使书写方便

应注意用宏定义表示数据类型和用 typedef 定义数据说明符的区别。宏定义只是简单的字符串替换,由预处理器来处理;而 typedef 是在编译阶段由编译器处理的,它并不是简单的字符串替换,而给原有的数据类型起一个新的名字,将它作为一种新的数据类型。

带参数的宏定义

//一般形式
#define 宏名(参数列表) 字符串
//带参调用的一般形式
宏名(实参列表);

栗子

#include<stdio.h>
#define MAX(a,b) ((a>b)?a:b)

int main()
{
    int x,y,max;
    printf("input two numbers:\n");
    scanf("%d %d",&x,&y);
    max=MAX(x,y);
    printf("max=%d\n",max);
    return 0;
}

对带参宏定义的说明

  • 带参宏定义中,形参之间可以出现空格,但是宏名和形参列表之间不能有空格出现。
  • 在带参宏定义中,不会为形式参数分配内存,因此不必指明数据类型。而在宏调用中,实参包含了具体的数据,要用它们去替换形参,因此实参必须要指明数据类型。
  • 在宏定义中,字符串内的形参通常要用括号括起来以避免出错
  • 对于带参宏定义不仅要在参数两侧加括号,还应该在整个字符串外加括号。
#的用法

#用来将宏参数转换为字符串,也就是在宏参数的开头和末尾添加引号

#include <stdio.h>
#define STR(s) #s
int main() {
    printf("%s\n", STR(hello world));
    printf("%s\n", STR("hello world"));
    return 0;
}
##的用法

##称为连接符,用来将宏参数或其他的串连接起来

C语言中几个预定义的宏

ANSI C 规定了以下几个预定义宏,它们在各个编译器下都可以使用:

  • LINE:表示当前源代码的行号
  • FILE:表示当前源文件的名称
  • DATA:表示当前的编译日期
  • TIME:表示当前的编译时间
  • STDC:当要求程序严格遵循ANSI C标准时该标识被赋值为1
  • __cplusplus:当编写C++程序时该标识符被定义。

栗子

#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("Line : %d\n", __LINE__);
    printf("Date : %s\n", __DATE__);
    printf("Time : %s\n", __TIME__);
    printf("File : %s\n", __FILE__);
    return 0;
}

C语言#if、##ifdef、#ifndef的用法详解,C语言条件编译详解

Windows 有专有的宏_WIN32,Linux 有专有的宏__linux__

栗子

#include <stdio.h>
int main(){
    #if _WIN32
        system("color 0c");
        printf("hello world\n");
    #elif __linux__
        printf("\033[22;31mhello world\n\033[22;30m");
    #else
        printf("hello world\n");
    #endif

    return 0;
}
#if用法的一般格式
#if 整形常量表达式1
	程序段1
#elif 整型常量表达式2
    程序段2
#elif 整型常量表达式3
    程序段3
#else
    程序段4
#endi

#if 命令要求判断条件为“整型常量表达式”,也就是说,表达式中不能包含变量,而且结果必须是整数;而 if 后面的表达式没有限制,只要符合语法就行。这是 #if 和 if 的一个重要区别。

ifdef的用法
#ifdef  宏名
    程序段1
#else
    程序段2
#endif

它的意思是,如果当前的宏已被定义过,则对“程序段1”进行编译,否则对“程序段2”进行编译。

VS/VC 有两种编译模式,Debug 和 Release。在学习过程中,我们通常使用 Debug 模式,这样便于程序的调试;而最终发布的程序,要使用 Release 模式,这样编译器会进行很多优化,提高程序运行效率,删除冗余信息。

栗子

#include <stdio.h>
#include <stdlib.h>
int main(){
    #ifdef _DEBUG
        printf("正在使用 Debug 模式编译程序...\n");
    #else
        printf("正在使用 Release 模式编译程序...\n");
    #endif

    system("pause");
    return 0;
}
ifndef的用法
#ifndef 宏名
    程序段1 
#else 
    程序段2 
#endif

与 #ifdef 相比,仅仅是将 #ifdef 改为了 #ifndef。它的意思是,如果当前的宏未被定义,则对“程序段1”进行编译,否则对“程序段2”进行编译,这与 #ifdef 的功能正好相反。

#error用法
//#error 指令用于在编译期间产生错误信息,并阻止程序的编译,其形式如下:
#error error_message
//例如,我们的程序针对 Linux 编写,不保证兼容 Windows,那么可以这样做:
#ifdef WIN32
#error This programme cannot compile at Windows Platform
#endif
//再如,当我们希望以 C++ 的方式来编译程序时,可以这样做:
#ifndef __cplusplus
#error 当前程序必须以C++方式编译
#endif

总结

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值