当前位置:网站首页>探索C语言程序奥秘——C语言程序编译与预处理
探索C语言程序奥秘——C语言程序编译与预处理
2022-06-24 22:08:00 【InfoQ】
1.代码如何编译
1.1从代码到程序

.c
1.2预编译
printf("That's wond\
erful!\n");
printf("That's wonderful\n!");
int/* 这看起来并不像一个空格*/fox;
int fox;
#
1.3编译,汇编,链接
- 语法分析
- 词法分析
- 语义分析
- 符号汇总
2.预处理
#define#include2.1预处理指令
- [ ] 宏定义。
#define指令定义一个宏,#undef指令删除一个宏定义。
- [ ] 文件包含。
#include指令会将一个指定文件的内容被包含到程序中。
- [ ] 条件编译。
#if、#ifdef、#ifndef、#elif、#else和#endif指令可以根据预处理器可以测试的条件来确定是将一段文本块包含到程序中还是将其排除在程序之外。
#error#line#pragma- 指令都以
#开始。#符号不需要在一行的行首,只要它之前只有空白字符就行。在#后是指令名,接着是指令所需要的其他信息。
- 在指令的符号之间可以插入任意数量的空格或水平制表符。例如,下面的指令是合法的∶
#define N 100
- 指令总是在第一个换行符处结束,除非明确地指明要延续。如果想在下一行延续指令,我们必须在当前行的末尾使用字符
\。
- 指令可以出现在程序中的任何地方。但我们通常将
#define和#include指令放在文件的开始,其他指令则放在后面,甚至可以放在函数定义的中间。
- 注释可以与指令放在同一行。实际上,在宏定义的后面加一个注释来解释宏的含义是一种比较好的习惯∶
#define N 48 /* max arr size */
2.2宏(#define)
2.2.1定义不带参数的宏
;标识符替换列表#define 标识符 替换列表
#define MAX 100
#define MIN 1
#define _CRT_SECURE_NO_WARNINGS 1 //vs编译器下,防止使用不安全函数而报错,如scanf。
#define reg register //为 register这个关键字,创建一个简短的名字
#define do_forever for(;;) //用更形象的符号来替换一种实现
#define CASE break;case //在写case语句的时候自动把 break写上。
// 如果定义的 被替换符 过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
date:%s\ttime:%s\n" ,\
__FILE__,__LINE__ , \
__DATE__,__TIME__ )
2.2.2定义带参数的宏
#define 标识符(x1,x2,….,xm) 替换列表
#define ADD(a,b) a+b //使用宏求两数之和
#define MAX(a,b) (a > b ? (a) : (b)) //使用宏求两数最大值
#define IS_EVEN(n) ((n) % 2 == 0) //使用宏定义判断是否为偶数的条件
//预处理前
i= MAX(j+k,m-n);
if(IS EVEN(i)) i++;
//预处理后
i =((j+k) > (m-n) ? (j+k) : (m-n));
if(((i) % 2 == 0)) i++;
2.2.3#和##
#####define PRINT(FORMAT, VALUE)\
printf("the value is "FORMAT"\n", VALUE);
...
PRINT("%d", 3);
//相当于
printf("the value is ""%d""\n", VALUE);
//等价与
printf("the value is %d\n", VALUE);
the value is 3
D:\gtee\C-learning-code-and-project\test_1005\Debug\test_1005.exe (进程 41188)已退出,代码为 0。
按任意键关闭此窗口. . .
int i = 10;
#define PRINT(FORMAT, VALUE)\
printf("the value of " #VALUE "is "FORMAT "\n", VALUE);
...
PRINT("%d", i + 3);
//相当于
printf("the value of " "i + 3" "is ""%d" "\n", i + 3);
//等价于
printf("the value of i + 3is %d\n", i + 3);
the value of i + 3is 13
D:\gtee\C-learning-code-and-project\test_1005\Debug\test_1005.exe (进程 31644)已退出,代码为 0。
按任意键关闭此窗口. . .
#######define ADD_TO_SUM(num, value) \
sum##num += value;
...
ADD_TO_SUM(5, 10);//作用是:给sum5增加10.
2.2.4宏与函数
#define MAX(a,b) (a > b ? (a) : (b)) //使用宏求两数最大值
- 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
- 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。
- 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
- 宏是没法调试的。
- 宏由于类型无关,也就不够严谨。
- 宏可能会带来运算符优先级的问题,导致程容易出现错。
#define MALLOC(num, type)\
(type *)malloc(num * sizeof(type))
...
//使用
MALLOC(10, int);//类型作为参数
//预处理器替换之后:
(int *)malloc(10 * sizeof(int));
- 把宏名全部大写
- 函数名不要全部大写
2.2.5使用宏的小贴士
- [ ] 宏的替换列表可以包含对其他宏的调用。例如,我们可以用宏
PI来定义宏TwO_PI∶
#define PI 3.14159
#define TWO_PI (2*PI)
TWO PI(2*PT)PI- [ ] 预处理器只会替换完整的记号,而不会替换记号的片断。因此,预处理器会忽略嵌在标识符、字符常量、字符串字面量之中的宏名。例如,假设程序含有如下代码行∶
#define SIZE 256
int BUFFER_SIZE;
if(BUFFER_SIZE > SIZE)
puts("Error: SIZE exceeded");
int BUFFER_SIZE;
if(BUFFER_SIZE >256)
puts ("Error:SIZE exceeded");
BUFFER_SIZEError∶SIZE exceededSIZE- [ ] 宏定义的作用范围通常到出现这个宏的文件末尾。由于宏是由预处理器处理的,它们不遵从通常的作用域规则。定义在函数中的宏并不是仅在函数内起作用,而是作用到文件末尾。
- [ ] 宏不可以被定义两遍,除非新的定义与旧的定义是一样的。小的间隔上的差异是允许的,但是宏的替换列表(和参数,如果有的话)中的记号都必须一致。
- [ ] 宏可以使用
#undef指令"取消定义"。#undef指令有如下形式∶
#undef 标识符
#undef N
NN#undef#undef- [ ] 在前面定义的宏的替换列表中有大量的圆括号。确实需要它们吗?答案是绝对需要。如果我们少用几个圆括号,宏有时可能会得到意想不到的(而且是不希望有的)结果。
2.2.6预定义宏
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义

2.3头文件包含(#include)
#include#include<文件名>
#include"文件名"

#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif //__TEST_H__
#pragma once
2.4条件编译
#if 常量表达式 //常量表达式为非0,则编译,否则不编译
...//选择编译取
#endif
printfprintf#define DEBUG 1
printf#if#endifif DEBUG
printf("Value of i : gd\n",i);
printf("Value of j: td\n",j);
#endif
#ifDEBUGDEBUG0printf#if#endifDEBUG0printf#if-#endifDEBUG1#if0DEBUG#if DEBUG
#if !DEBUG
defineddefined 10defined#if#if defined(DEBUG)
#endif
DEBUG#if#endifDEBUG#if defined DEBUG
definedDEBUGDEBUG#ifdef#ifndef#ifdef#ifdef#ifndef#if#ifdef 标识符//相当于 #if defined 标识符
当标识符被定义为宏时需要包含的代码
#endif
#ifndef 标识符//相当于 #if defined !标识符
当标识符被定义为宏时需要包含的代码
#endif
#include <stdio.h>
#define __DEBUG__ 1
int main()
{
int i = 0;
int arr[10] = { 0 };
for (i = 0; i < 10; i++)
{
arr[i] = i;
#ifdef __DEBUG__
printf("%d\n", arr[i]);//观察数组是否赋值成功。
#endif //__DEBUG__
}
return 0;
}
#if#ifdef#ifndefif#endif#if #elif#else#elif#else#if#ifdef#ifndef#if 表达式1
当表达式1非0时需要包含的代码
#elif 表达式2
当表达式1为0,但表达式2非0时需要包含的代码
#else
其他情况下需要包含的代码
#endif
2.4其他预处理指令
#error#error 消息
#errorError directive∶消息#error 消息#error#line#line#line n
#line n "file name"
#pragma#pragma#pragma #pragma 记号
//如
#pragma pack() //vs编译器有使用
#pragma once //vs中防止包含重复头文件
#pragma#pragma#pragma#pragma边栏推荐
- Some Modest Advice for Graduate Students - by Stephen C. Stearns, Ph.D.
- 2个NPN三极管组成的恒流电路
- Build and train your own dataset for pig face recognition
- uni-app集成极光推送插件后真机调试提示“当前运行的基座不包含原生插件[JG-JPush]...”问题的解决办法
- After integrating the aurora push plug-in in the uni app, the real machine debugging prompts "the currently running base does not contain the native plug-in [jg-jpush]..." Solutions to problems
- Chrysanthemum chain (winter vacation daily question 39)
- Cusdis - 轻量级、隐私优先的开源评论系统 | 倾城之链
- Some Modest Advice for Graduate Students - by Stephen C. Stearns, Ph.D.
- Google browser console F12 how to set the Chinese / English switching method, we must see the last!!!
- Dataease template market officially released
猜你喜欢

How to prepare for the last day of tomorrow's exam? Complete compilation of the introduction to the second building test site

2个NPN三极管组成的恒流电路

Fatigue liée à l'examen du marché secondaire des médicaments innovants: succès clinique de la phase III et approbation du produit

Baidu voice synthesizes voice files and displays them on the website

DDD概念复杂难懂,实际落地如何设计代码实现模型?
![Experiment 5 8254 timing / counter application experiment [microcomputer principle] [experiment]](/img/e2/7da59a566e4ccb8e43f2a64c0420e7.png)
Experiment 5 8254 timing / counter application experiment [microcomputer principle] [experiment]
![uni-app集成极光推送插件后真机调试提示“当前运行的基座不包含原生插件[JG-JPush]...”问题的解决办法](/img/8b/0e982711c225ec8b0a2b90819d8a11.png)
uni-app集成极光推送插件后真机调试提示“当前运行的基座不包含原生插件[JG-JPush]...”问题的解决办法

Abnova a4gnt polyclonal antibody
![Search two-dimensional matrix [clever use of bisection + record solution different from inserting bisection]](/img/c9/afc03afd477bbfdd3c0dc54bacfd2d.png)
Search two-dimensional matrix [clever use of bisection + record solution different from inserting bisection]

MeterSphere開源持續測試平臺與阿裏雲雲效DevOps的集成
随机推荐
Award winning interface control development kit devaxpress v22.1 officially announced
Status quo analysis: how "one cloud and multi-core" can promote the rapid deployment of information innovation projects
Basic use of transformers Library
放养但没有完全放养(春季每日一题 2)
带马尔科夫切换的正向随机微分方程数值格式模拟
2022-06-24:golang选择题,以下golang代码输出什么?A:1;B:3;C:4;D:编译失败。 package main import ( “f
弹性蛋白酶中英文说明书
Abnova丨A4GNT多克隆抗体中英文说明
TSDB在民机行业中的应用
Redis persistence
Some Modest Advice for Graduate Students - by Stephen C. Stearns, Ph.D.
Deoxyribonuclease I instructions in Chinese and English
Fake wireless speakers in stores? Sony responded: the product has reserved a wired connection interface, which can be used in complex scenarios
明日考试 最后一天如何备考?二造考点攻略全整理
Excel Chinese character to pinyin "suggestions collection"
MeterSphere开源持续测试平台与阿里云云效DevOps的集成
excel 汉字转拼音「建议收藏」
如何选择正规安全的外汇交易平台?
困牛排序(寒假每日一题 40)
搜索二维矩阵[二分巧用 + 记录不同于插入二分的解法]