当你敲完Hello World后的第一步——C

简介: 当你敲完Hello World后的第一步——C

“江山如画,一时多少豪杰——时二二年五月六日”


这里是目录

前言

一、#define指令

1.#define定义宏

2.#define 替换 宏

3.带副作用的宏参数

4.#undef撤销宏定义

5.宏和函数对比(重点)

二、条件编译指令

1.单分支

2.多分支条件编译

3.判断某个符号是否被定义

4.嵌套指令

三、#include指令

1.本地文件包含

2.库文件包含

3.嵌套文件包含


前言

了解敲完hello world后,编译器是怎么处理代码的第一步的呢,这是学习C和C++的基础。

Hello World代码如下。放错了,重来。

代码如下


当你敲完Hello World这串代码时。编译器会对这些代码进行编译 和 链接的操作。


而 编译: 又分为 预处理、编译、汇编。

所以说 当你敲完C代码后的第一步,编译器会对C代码进行预处理.


那么预处理主要做了那些事情呢?


预处理大致做了以下事情:

1.定义和替换由 #define指令定义的符号

2.删除注释

3.确定代码部分内容是否应该根据一些 条件编译指令 进行编译

4.插入被 #include指令包含的内容


所以本章详解预处理指令 #define、#include、条件编译指令。


一、#define指令

1.#define定义宏

什么是宏?

宏的定义:#define 允许把参数替换到文本中,这种实现通常称为定义宏

宏的声明格式

#define NAME stuff

解释:没当有符号name出现在#define NAME stuff这条语句后面时,预处理器就会把它替换为 stuff。

NAME:

1.NAME是宏的名字。在这里 name 相当于变量,或者也可以相当于函数。但不等于函数!

2.一般NAME都是大写,因为宏和函数语法很相似,语言本身我们无法区分,所以宏名要全部大写

stuff:可以是常量。可以是表达式。也可以是一段程序。


例如:

以下代码在预处理后是什么样子呢?

//定义声明宏
//定义中我们使用了括号,这是一个好习惯,避免优先级的错误
#define SQUARE(x)  (x)*(x)
int main()
{
  printf("%d ", SQUARE(5));
  return 0;
}

预处理后的代码,以下你看到的代码是编译器实实在在的处后的代码。

#define SQUARE(x)  (x)*(x)
int main()
{
  //将SQUARE(5)替换为(5)*(5)
  printf("%d ", (5)*(5));
  return 0;
}

你是否还对#define 替换迷惑?请继续往下看


2.#define 替换 宏

到底上面的代码是怎么替换的 宏?

1.再调用宏时,首先对参数检查,看是否包含了#define定义的符号,比如SQUARE(5),然后将它的x * x替换为5 * 5.

2.对于宏,参数名被他们的值所替代。

3.最后,再次对文本扫描,看是否包含了热任何由#define定义的符号。如果是,就重复上述处理过程。


为什么会有第3步的重复呢?

因为有时候#define定义可以包含其他#define定义的符号。但是宏不可以递归!


3.带副作用的宏参数

什么是带副作用的宏参数?

副作用:就是表达式求值的时候出现的永久性效果

例如:

x+1;//不带副作用
x++;//带有副作用

下面代码输出结果是什么?

#include <stdio.h>
#define ADD(a, b) (a)+(b)
int main()
{
  int x = 2; 
  int y = 3; 
  int z = ADD(x++, y++);
  //输出的结果是什么?
  //x=3 y=4 z=5
  printf("x=%d y=%d z=%d\n", x, y, z);
  return 0;
}

因为被替换的代码是int z = ADD(x++, y++);

替换后为:int z = (x++)+(y++);

这样结果就一目了然。

4.#undef撤销宏定义

#undef:这条指令用于移除一个宏定义

例如:移除MAX这个宏。


5.宏和函数对比(重点)

image.png


二、条件编译指令

什么是条件编译?

意思就是我们可以选择性的编译。

条件编译:你可以选择代码的一部分是被正常编译还是完全忽略。用于支持条件编译的基本结构是#if指令和与其匹配的#endif指令。


1.单分支

常量表达式expression,由预处理器求值。

如果expression为真,那么statements将被执行,否则预处理器就安静的删除它们。


#if expression
 statements;
#endif
//常量表达式expression,由预处理器求值。


2.多分支条件编译

同if else语句,为真则执行。

#if expression
 //...
#elif expression
 //...
#else
 //...
#endif

3.判断某个符号是否被定义

为了测试一个符号是否已经被定义。在条件编译中完成这个任务更方便。

以下两条语句功能想通过。

1.#if defined(symbol)
2.#ifdef symbol


4.嵌套指令

某个程序既要在windows系统下能够运行,也需要在Linux系统下运行,这就要条件编译来解决跨平台问题。这时候嵌套指令很容易解决。

#if defined(OS_UNIX)
   #ifdef OPTION1
       unix_version_option1();
   #endif
   #ifdef OPTION2
      unix_version_option2();
   #endif
#elif defined(OS_MSDOS)
   #ifdef OPTION2
      msdos_version_option2();
   #endif
#endif


三、#include指令

#include在预处理时会被展开。

这种展开的方式很简单:

1.预处理器先删除这条指令,并用**#include**所包含文件的内容替换。

2.这样一个源文件被包含10次,那就实际被编译10次。

1.本地文件包含

#include "Add.h"

查找方法

1.先在源文件所在目录下查找

2.如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。

2.库文件包含

#include <stdio.h>

查找方法:查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。


这样是不是可以说,对于库文件也可以使用 “” 的形式包含?

答案是肯定的,可以。

但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了。


3.嵌套文件包含

有时候会重复包含头文件,以前为了解决这个方法,人们用了条件编译。代码如下

每个头文件的开头写:


例如有个test.h的头文件。用下划线分开头文件。全大写。

#ifndef __TEST_H__
#define __TEST_H__
//这里面写头文件的内容
#endif  

上面这种写法比较古老。

现在一般用这个写法

#pragma once

#pragma once也是是用来防止头文件被包含的。


相关文章
|
开发框架 JavaScript 前端开发
【App Service】解决 .NET Profiler 报告打开后无数据加载的问题
【App Service】解决 .NET Profiler 报告打开后无数据加载的问题
116 0
|
分布式计算 网络协议 大数据
大数据开发基础的计算机网络的TCP/UDP协议
计算机网络是大数据开发中不可或缺的一部分,而TCP/UDP协议则是计算机网络中最基础的通信协议之一。本篇文章将为大家介绍TCP/UDP协议的基本概念、工作原理以及应用场景。
198 0
|
数据可视化 数据挖掘 Linux
Python数据分析—Pandas可视化
Python数据分析—Pandas可视化
198 0
Python数据分析—Pandas可视化
|
算法 测试技术 API
APP兼容性(2)- 揭秘岩鼠智能遍历
Android APP兼容性测试一直都是广大开发者极为头痛的事情,究竟如何入手才好呢?UC研发效能分享内部经验,供大家参考!
2308 0
APP兼容性(2)- 揭秘岩鼠智能遍历
|
机器学习/深度学习 算法框架/工具 Python
Stanford CS231n实践笔记(课时22卷积神经网络工程实践技巧与注意点 cnn in practise 上)
本课主要2个实践内容:1、keras中数据集丰富,从数据集中提取更多特征(Data augmentation) 2、迁移学习(Tranform learning) 代码:https://github.com/jsxyhelu/DateSets 1、keras中数据集丰富,从数据集中提取更多特征(Data augmentation) keras是比较现代化的DL工具,所以这方面的功能都是具备的。
1230 0
|
移动开发 weex Android开发
weex起步
weex文档地址:http://weex-project.io/cn/guide/index.html weex的文档过于简单,加上js语法 & android & ios本身也有很多的问题,导致新接触weex,几乎步步是坑 在此记录一下weex的一些探索 一、初始化 按照官方的步骤走, #安装node .
1235 0
|
8天前
|
人工智能 运维 安全
|
6天前
|
人工智能 异构计算
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
敬请锁定《C位面对面》,洞察通用计算如何在AI时代持续赋能企业创新,助力业务发展!
|
7天前
|
机器学习/深度学习 人工智能 自然语言处理
B站开源IndexTTS2,用极致表现力颠覆听觉体验
在语音合成技术不断演进的背景下,早期版本的IndexTTS虽然在多场景应用中展现出良好的表现,但在情感表达的细腻度与时长控制的精准性方面仍存在提升空间。为了解决这些问题,并进一步推动零样本语音合成在实际场景中的落地能力,B站语音团队对模型架构与训练策略进行了深度优化,推出了全新一代语音合成模型——IndexTTS2 。
639 22
|
7天前
|
人工智能 测试技术 API
智能体(AI Agent)搭建全攻略:从概念到实践的终极指南
在人工智能浪潮中,智能体(AI Agent)正成为变革性技术。它们具备自主决策、环境感知、任务执行等能力,广泛应用于日常任务与商业流程。本文详解智能体概念、架构及七步搭建指南,助你打造专属智能体,迎接智能自动化新时代。