C语言程序环境和预处理Pt.2 - 宏的命名约定|#undef|命令行定义|条件编译

本文主要是介绍C语言程序环境和预处理Pt.2 - 宏的命名约定|#undef|命令行定义|条件编译,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Pt1:

C语言程序环境和预处理Pt.1 - 预处理指令|预处理操作符-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/BuiderCodes/article/details/136620859


1.宏的命名约定

  1. 清晰明了:宏的名称应该清晰地表达其功能或目的,使读者能够迅速理解其作用。注意不要使用中文拼音!这样的宏名很难以理解,用英文单词会使读者快速理解。

  2. 使用大写字母:通常约定宏名称全部使用大写字母,以便与函数区别开来,因为函数一般用小写命名,这样能更好区分宏和函数。

  3. 下划线分隔:在多个单词构成的宏名称中使用下划线分隔,以增强可读性。例如:MAX_LENGTH

  4. 避免与关键字冲突:确保宏名称不与语言的关键字或其他已经存在的标识符冲突。

2. #undef 

#undef 是一个预处理器指令,用于取消定义一个已经定义的宏。通过#undef,可以在之后重新定义或者删除已经定义的宏。

例如,运行下面这段代码,将会输出

“MAX”未定义;假设外部返回 int

#define MAX(x,y) ((x)>(y))?(x):(y)
int main()
{int a = 1;int b = 2;int c = MAX(a, b);
#undef MAXint d = MAX(a, b);return 0;
}

3. 命令行

在命令行中,可以使用 -D 选项来定义一个宏。这在编译时可以用来传递参数给预处理器。

例如,在使用 GCC 编译器时,我们可以通过下面这个指令来定义宏:

gcc -DDEBUG main.c -o main

4.条件编译 

条件编译指令是在编译过程中根据预定义的条件选择性地包含或排除代码块。主要的条件编译指令包括:

 #ifdef:检查某个宏是否已经定义,如果定义了,则编译后面的代码块。

#ifdef DEBUG// 在 DEBUG 模式下执行的代码
#endif

要注意,与if不同的是,#ifdef 后面的判断内容不用加括号,而且,if判断为假不会删除代码块里面的内容,而编译指令#ifdel做的事是直接在预处理阶段对条件做判断,为假直接删除代码块内的内容。

#ifndef:与 #ifdef 相反,检查某个宏是否未定义,如果未定义,则编译后面的代码块。

#ifndef DEBUG// 在非 DEBUG 模式下执行的代码
#endif
#ifndef DEBUG// 在非 DEBUG 模式下执行的代码
#endif

#if:基于表达式的结果来选择性地编译代码块。

#if defined(DEBUG) && DEBUG == 1// 在 DEBUG 定义且值为 1 时执行的代码
#endif

#if 决定的是什么条件下编译什么代码,而if决定的是什么情况下执行什么代码。

#elif:在多个条件之间进行选择,与 #if 或 #ifdef 一起使用。

#ifdef DEBUG// 在 DEBUG 模式下执行的代码
#elif defined(TEST)// 在 TEST 模式下执行的代码
#else// 默认情况下执行的代码
#endif

#else与 #ifdef 或 #ifndef 一起使用,指定未满足前面条件时要编译的代码块。

#ifdef DEBUG// 在 DEBUG 模式下执行的代码
#else// 在非 DEBUG 模式下执行的代码
#endif

#endif:结束条件编译块。

#ifdef DEBUG// 在 DEBUG 模式下执行的代码
#endif

 上述指令还可以嵌套使用,比如

#ifdef OS_UNIX#ifdef OPTION1unix_version_option1();#endif#ifdef OPTION2unix_version_option2();#endif
#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2();#endif	
#endif

条件编译用在开发跨平台应用程序时,可能需要根据不同的操作系统或编译器设置不同的编译选项。条件编译可以根据不同平台的特性选择性地编译适配的代码。

比如一份代码为windows和linux两个平台各写了一份代码,就可以用条件编译指令来编译对应平台的代码。

5.文件包含

C语言中的头文件包含是通过 #include 预处理指令实现的。例如,#include <stdio.h> 将标准输入输出库的声明包含到程序中,使得 printf() 函数可以被使用。

C语言中的包含方法有两种:

  1. 使用尖括号`<>`

    这种方式用于包含标准库头文件或系统提供的头文件。编译器会在系统默认的路径中查找这些头文件。
    如果在系统默认路径下找不到则会报错。
  2. 使用双引号`""`
    这种方式用于包含自定义的头文件或者当前工作目录下的头文件。编译器会先在当前目录下查找头文件,如果找不到再去系统默认路径查找

那是否就是说所有的文件都可以用`""` 来包含呢?

理论上是可以的,但是这样做查找的效率就会变低,而且这样也容易混淆库文件和本地文件。

 现在再来看看这样的情况:

pub.h是公用模块,test1和test2同时调用了pub.h,而test又同时调用了test1 和 test2,这样一来,test.h中就包含了两份pub.h的内容,为了避免这种情况,我们有两种解决方法:

1. 使用条件编译

#ifndef __PUB_H__
#define __PUB_H__//pub.h的内容#endif

我们看到很多系统头文件里面的条件编译语句都是为了防止文件重复包含的。 

 2.使用#pragma once

#pragma once//pub.h的内容

     

这篇关于C语言程序环境和预处理Pt.2 - 宏的命名约定|#undef|命令行定义|条件编译的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/830357

相关文章

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

C语言进阶(预处理命令详解)

《C语言进阶(预处理命令详解)》文章讲解了宏定义规范、头文件包含方式及条件编译应用,强调带参宏需加括号避免计算错误,头文件应声明函数原型以便主函数调用,条件编译通过宏定义控制代码编译,适用于测试与模块... 目录1.宏定义1.1不带参宏1.2带参宏2.头文件的包含2.1头文件中的内容2.2工程结构3.条件编

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤

Java JDK1.8 安装和环境配置教程详解

《JavaJDK1.8安装和环境配置教程详解》文章简要介绍了JDK1.8的安装流程,包括官网下载对应系统版本、安装时选择非系统盘路径、配置JAVA_HOME、CLASSPATH和Path环境变量,... 目录1.下载JDK2.安装JDK3.配置环境变量4.检验JDK官网下载地址:Java Downloads

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker