程序环境和预处理

86 阅读3分钟

程序环境和预处理

c333.png

cc366.png

1.程序的翻译环境和执行环境

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

预定义符号

dd222.png

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

# define是定义符号的

# define M 1000

int main()
{
	int m = M;

	printf("%d", m);
	return 0;
}

# define是定义宏

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

  • #define name( parament-1ist ) stuff 其中的 parament-7ist是一个由逗号隔开的符号表,它们可能出现在stuff中.

  • 参数列表的左括号必须与name紧邻

  • 如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

// # define 定义宏
# define SQUARE(x) x*x

int main()
{
	printf("%d", SQUARE(3));// 3 * 3

	return 0;
}

// ------------------------------------------------------------

// # define 定义宏 括号很重要
# define SQUARE(x) ((x) * (x))

int main()
{
	printf("%d", SQUARE(3));// 3 * 3

	// 宏的参数完全替换的 不是先计算在 传递
	printf("%d", SQUARE(3+1));// 7
	// 3 + 1 * 3 +1

	return 0;
}

#define替换规则

  • 在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
  1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
  2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
  3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。

# define M 1000
# define MAX(x,y) y+x
int main()
{
	// 这里的 M 不是传递,是替换
	int max = MAX(100, M);
	printf("%d", max);// 1100

	return 0;
}

注意:

  1. 宏参数和#defire定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。

  2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

#和##

  • 如何把参数插入到字符串中?
# define PRINT(x) printf("the value of " #x " is %d \n",x)
int main()
{
	// printf("hello world \n");
	// printf("hello" "world \n"); // 相同

	int a = 10;
	PRINT(a);

	int b = 20;
	PRINT(b);

	int c = 20;
	PRINT(c);

	return 0;
}

宏的副作用参数

# define MAX(X,Y)((X) > (Y) ? (X) : (Y))

int main()
{
	int a = 5, b = 8;
	// 副作用替换
	int m = MAX(a++, b++);
	// ((a++) > (b++) ? (a++) : (b++))

	printf("%d %d \n", a, b);// 6 10

	printf("M = %d", m);// 9
	return 0;
}

宏和函数对比

  • 宏通常被应用于执行简单的运算。比如在两个数中找出较大的一个。

  • 那为什么不用函数来完成这个任务?

  • 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。

  • 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。

  • 当然和宏相比函数也有劣势的地方:

  • 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。

  • 宏是没法调试的。

  • 宏由于类型无关,也就不够严谨。

  • 宏可能会带来运算符优先级的问题,导致程容易出现错。

  • 宏有时候可以做函数做不到的事情。比如:宏的参数可以出现类型,但是函数做不到。

#undef 取消宏

  • 移除一个宏定义

未完...