#define定义

C语言中define的使用及宏与函数对比

1.define定义常量

比如

#define max  100

我们就可以用max来代替100使用了。

#define saying "hello world"

我们就可以使用saying代替"hello,world"使用了

但是要注意的是,我们最好不要在最后面加上分号,有时候容易出错

比如

#include <stdio.h>
#define a 0;
int main(void)
{
	int b;
	if (0)
		b = a;
	else
		b = 1;
	return 0;
}

这个时候a替换过去就是

b=a;;

编译器会吧b=a;识别成一条语句

;识别出另一条语句(空语句)

这个时候if没加括号,就会导致if else使用出错。

2.define 定义宏

我们直接上例子理解

这个地方的宏类似于函数,但是又不同于函数(后面会解释) 

cal(a)就是 4*4=16没问题

但是为啥cal(b)就等于23呢?

#define无论是定义常量还是宏,都是预处理的时候直接替换的

也就是cal(b)=cal(3+5)=3+5*3+5=3+15+5=23;

因此我们在使用宏的时候,不要吝啬括号。

所以用于对数值表达式进行求值的宏定义都应用这种方式加上括号,避免在使用宏时由于参数中的操作符或临近操作符之间不可预料的相互作用,

 因此像这样改就可以了

但是要注意定义宏时要将宏的名字紧挨左括号,不然如果有空隙就成了定义常量了

注意:最好不要使用带有副作用的参数
当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。

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

#include <stdio.h>
#define cal(a,b) ((a++)>(b++)?(a++):(b++)) 
int main(void)
{
	int a = 4;
	int b = 3;
	printf("%d\n", cal(a,b));
	printf("%d\n", a);
	return 0;
}

比如这串代码,虽然cal(a,b)的的值是5,但是此时再去打印a就是6了,如果我们不打印的话,就很容易将a的值当作5去使用,而且根据a和b的值大小不同,a++,b++的次数也不固定,很容易导致不可预测的后果,因此不要使用带有副作用的宏。

总结:

宏替换的规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1.在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。

如果是,它们首先被替换。
2.替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上
述处理过程。
注意:
1.宏参数和#define定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2.当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被拽索

比如

#include <stdio.h>
#define cal(a,b) ((a++)>(b++)?(a++):(b++)) 
int main(void)
{
	int a = 4;
	int b = 3;
	printf("cal(a,b)");
	return 0;
}

这个时候打印出来的结果就是字符串cal(a,b)

3.宏和函数的优劣

接下来我们来看函数和宏的优缺点

和函数相比宏的劣势:
1.每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2.宏是没法调试的。
3.宏由于类型无关,也就不够严谨。
4.宏可能会带来运算符优先级的问题,导致程容易出现错。

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

#include <stdio.h>
#include <stdlib.h>
#define MALLOC(n,type) (type*)malloc(n*sizeof(type)) 
int main(void)
{
	int* a = MALLOC(20, int);
	return 0;
}

宏这个地方就可以传类型了,这是函数做不到的

最后以一张表格来对比宏和函数优劣

3.#运算符和##运算符

(1)#运算符

、比如说我们希望做一个宏或者函数

假设int a=3  float b=4

比如输入 "%d",a

打印出来the value of a is 3

输入 "%f" ,b

打印出来是the value of b is 4

显然这用函数是无法实现的

因为the value of is 3

a

是不可变的,我再输入 "%f" ,b

打印出来的是the value of a is 4

那我们来一串宏试试可不可行

#include <stdio.h>
#include <stdlib.h>
#define WORK(format,n)  printf("the value of n is "format"\n",n)
int main(void)
{
	int a = 4;
	WORK("%d", a);
	return 0;
}

 但是我们这个时候发现这个宏也无法解决这个问题,打印出来的是the value of n is 4

而不是the value of a is 4

 这个时候我们的#运算符就可以起到作用了,但是再此之前我们要回顾一点

就是两个连续的字符串会被自动连接一个字符串

因此我们就可以这样写代码

这样就可以达到我们的效果了

#运算符
运算符将宏的一个参数转换为字符串字面量。

它仅允许出现在带参数的宏的替换列表中。
#运算符所执行的操作可以理解为”字符串化“。

我们输入 "%d",a

会变成printf("the value of " "a" " is "format"\n",n);

(2)##运算符

## 运算符
## 可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符。#被称为记号粘合
这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
比如说我们比较两个数的大小,int类型的值比较要写一个函数,浮点数类型的还要写一个函数,太麻烦了。

使用宏可以很好的解决问题

#include <stdio.h>
#include <stdlib.h>
#define GENERIC_MAX(type)\
type type##_max(type x,type y)\
{                             \
return (x > y ? x : y);       \
}
GENERIC_MAX(float)//替换到宏体后float##_max生成新的符号 int_max做函数名
GENERIC_MAX(int)//替换到宏体后int##_max生成新的符号 float_max做函数名
int main(void)
{
	//调用函数
	int m = int_max(2, 3);
	printf("%d\n", m);
	float n = float_max(2.5f, 3.5f);
	printf("%f\n", n);
	return 0;
}

一个宏声明未结束,句尾要加上\符

(3) #undef
这条指令用于移除一个宏定义。

(4)命名约定
-般来讲函数的宏的使用语法很相似。所以语言本身没法帮我们区分二者。
那我们平时的一个习惯是:
把宏名全部大写
函数名不要全部大写

<think>我们正在讨论C语言中如何使用#define定义字符串常量。根据引用[1],我们知道#define的基本用法是为标识符赋值,包括数值和字符串。引用[2]则介绍了#运算符用于字符串化,但这里我们更关注直接定义字符串常量。在C语言中,使用#define定义字符串常量有两种常见方式:1.直接定义整个字符串为常量。2.使用#运算符将宏参数转换为字符串(但这属于带参数的宏,我们这里先讨论简单定义)。例如,我们可以这样定义一个字符串常量:#defineGREETING"Hello,World!"这样,在代码中所有出现GREETING的地方都会被替换为"Hello,World!"。另外,我们也可以定义多个字符串,或者使用转义字符。下面给出具体示例和说明。</think>在 C 语言中,使用 `#define` 定义字符串常量有两种主要方式: ### 1. 直接定义字符串字面量 这是最常用的方法,使用双引号包裹字符串: ```c #define GREETING "Hello, World!" #define FILE_PATH "C:\\Documents\\file.txt" #define WARNING_MSG "⚠️ Critical system error!" ``` **使用示例:** ```c #include <stdio.h> #define WELCOME_MSG "Welcome to the program!" #define EXIT_PROMPT "Press any key to exit..." int main() { printf("%s\n", WELCOME_MSG); // 输出:Welcome to the program! printf("%s\n", EXIT_PROMPT); // 输出:Press any key to exit... return 0; } ``` ### 2. 使用 `#` 运算符(字符串化) 通过 `#` 运算符将宏参数转换为字符串字面量: ```c #define STRINGIFY(x) #x #define TO_STRING(x) STRINGIFY(x) ``` **使用示例:** ```c #include <stdio.h> #define VERSION 2.1.5 #define STRINGIFY(x) #x #define VERSION_STR STRINGIFY(VERSION) int main() { printf("App version: %s\n", VERSION_STR); // 输出:App version: 2.1.5 printf("File: %s\n", STRINGIFY(main.c)); // 输出:File: main.c return 0; } ``` ### 关键注意事项: 1. **转义特殊字符**:路径中的反斜杠需要双写 ```c #define LOG_FILE "C:\\logs\\app.log" // 正确 #define BAD_PATH "C:\logs\app.log" // 错误(会触发警告) ``` 2. **多行字符串**:使用反斜杠 `\` 连接 ```c #define MULTI_LINE "Line 1\n" \ "Line 2\n" \ "Line 3" ``` 3. **与字符常量的区别**: ```c #define CHAR_A 'A' // 字符常量(单引号) #define STR_A "A" // 字符串常量(双引号) ``` 4. **拼接技巧**:相邻字符串会自动拼接 ```c #define NAME "Alice" printf("Hello " NAME "!\n"); // 输出:Hello Alice! ``` > ⚠️ 注意:`#define` 是预处理指令,在编译前进行文本替换,不进行类型检查[^1]。定义字符串常量时通常使用全大写字母命名(如 `MAX_PATH`)以区别于变量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值