程序环境和预处理

一、程序的翻译环境和执行环境

  • 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
  • 第2种是执行环境,它用于实际执行代码。

二、详解编译与链接

在这里插入图片描述

三、预处理详解

3.1 #define定义宏

#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。

下面是宏的申明方式:
#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。

#include <stdio.h>
#define POW(x) x*x
int main()
{
	int n = 5;
	int sum = POW(5 + 1);
	printf("%d", sum);//11  注意 是把5+1替换到x里面去了
	return 0;
}

3.2 #和##

一个#,把一个宏参数变成相应的字符串

#include <stdio.h>
#define PRINT(FORMAT,VALUE) printf("the value of " #VALUE " is "FORMAT "\n", VALUE)
int main()
{
	int i = 10;
	PRINT("%d", i + 3);
	return 0;
}
//the value of i + 3 is 13

两个##,把两边符号合成一个符号

#include <stdio.h>
#define ADD_TO_SUM(num,value) sum##num += value;
int main()
{
	int sum5 = 10;
	int sum = ADD_TO_SUM(5, 10);
	printf("%d ", sum);//20
	return 0;
}

3.3 带副作用的宏参数

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。
例子

#include <stdio.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
	int x = 5;
	int y = 4;
	int num = MAX(x++, y++);
	printf("num=%d a=%d b=%d", num, x, y);//num=6 x=7 y=5
	return 0;
}

四、宏和函数的对比

属性#define定义宏函数
代码长度每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码
执行速度更快存在函数的调用和返回的额外开销,所以相对慢一些
操作符的优先级宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写时候多些括号。函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测
带有副作用的参数参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。函数参数只在传参的时候求值一次,结果更容易控制。
参数类型宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的
调试宏是不方便调试的函数是可以逐语句调试的
递归宏是不能递归的函数是可以递归的

五、条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。
常见的条件编译指令:

1.
#if 常量表达式
      //...
#endif
//常量表达式由预处理器求值。
如:
#define __DEBUG__ 1
#if __DEBUG__
     //..
#endif

2.多个分支的条件编译
#if 常量表达式
     //...
#elif 常量表达式
     //...
#else
    //...
#endif

3.判断是否被定义
#if defined(symbol)
#ifdef symbol

#if !defined(symbol)
#ifndef symbol

4.嵌套指令
#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 “filename”

查找侧略:先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。

  • 库文件包含

#include <filename.h>

查找策略:直接去标准路径下查找。

如何解决头文件重复包含问题?

#ifndef TEST_H
#define TEST_H
#endif

或者

#pragma once

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sense the warmth

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值