目录
- 1. #运算符
- 2. ##运算符
- 3. 条件编译
- 4. 题目分享
- 总结
正文开始
前言: 本章为C语言语法完结撒花, 下文将进行C语言中#和##操作符以及条件编译的讲解, 来进一步让我们了解C语言.
作者主页: 酷酷学!!!
1. #运算符
#运算符将宏的⼀个参数转换为字符串字⾯量。它仅允许出现在带参数的宏的替换列表中。
#运算符所执⾏的操作可以理解为”字符串化“。
当我们有⼀个变量 int a = 10; 的时候,我们想打印出: the value of a is 10 .
就可以写:
#define PRINT(n) printf("the value of "#n " is %d", n);
当我们按照下⾯的⽅式调⽤的时候:
PRINT(a);//当我们把a替换到宏的体内时,就出现了#a,⽽#a就是转换为"a",时⼀个字符串
代码就会被预处理为:
printf("the value of ""a" " is %d", a);
运⾏代码就能在屏幕上打印:
the value of a is 10
2. ##运算符
##可以把位于它两边的符号合成⼀个符号,它允许宏定义从分离的⽂本⽚段创建标识符。 ## 被称为记号粘合
这样的连接必须产⽣⼀个合法的标识符。否则其结果就是未定义的。
这⾥我们想想,写⼀个函数求2个数的较⼤值的时候,不同的数据类型就得写不同的函数。
int int_max(int x, int y)
{return x>y?x:y;
}
float float_max(float x, float y)
{return x>y?x:y;
}
但是这样写起来太繁琐了,现在我们这样写代码试试:
//宏定义
#define GENERIC_MAX(type) \
type type##_max(type x, type y)\
{ \return (x>y?x:y); \
}
使⽤宏,定义不同函数
GENERIC_MAX(int) //替换到宏体内后int##_max ⽣成了新的符号 int_max做函数名
GENERIC_MAX(float) //替换到宏体内后float##_max ⽣成了新的符号 float_max做函数名
int main()
{//调⽤函数 int m = int_max(2, 3);printf("%d\n", m);float fm = float_max(3.5f, 4.5f);printf("%f\n", fm);return 0;
}
输出:
3
4.500000
3. 条件编译
在编译⼀个程序的时候我们如果要将⼀条语句(⼀组语句)编译或者放弃是很⽅便的。因为我们有条件编译指令。
⽐如说:
调试性的代码,删除可惜,保留⼜碍事,所以我们可以选择性的编译。
#include <stdio.h>
#define __DEBUG__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;
}
常⻅的条件编译指令:
1.
#if 常量表达式
//...
#endif
//常量表达式由预处理器求值。
如:
#define __DEBUG__ 1
#if __DEBUG__
//..
#endif2.多个分⽀的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif3.判断是否被定义
#if defined(symbol)
#ifdef symbol#if !defined(symbol)
#ifndef symbol4.嵌套指令
#if defined(OS_UNIX)#ifdef OPTION1unix_version_option1();#endif#ifdef OPTION2unix_version_option2();#endif#elif defined(OS_MSDOS)#ifdef OPTION2msdos_version_option2();#endif#endif
4. 题目分享
- 写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明
考察:offsetof宏的实现
#include<stdio.h>
#define offset(structType, MemberName) ((size_t)&((structType*)0)->MemberName)struct stu
{char name[10];int age;char sex[10];
};int main()
{size_t ret = 0;ret = offset(struct stu, age);printf("%d\n", ret);return 0;
}
运行结果:
代码分析:
//Struct是结构体类型名,MenberName是成员名.
//1、先将0转换为一个结构体类型的指针,
// 相当于某个结构体的首地址是0。
// 此时,每一个成员的偏移量就成了相对0的偏移量,
// 这样就不需要减去首地址了。
//
//2、对该指针用->访问其成员,并取出地址,
// 由于结构体起始地址为0,此时成员偏移量直接相当于对0的偏移量,
// 所以得到的值直接就是对首地址的偏移量。
//
//3、取出该成员的地址,强转成size_t并打印,就求出了这个偏移量。
- 写一个宏,可以将一个整数的二进制位的奇数位和偶数位交换。
#define SWAP_BITS(num) (((num & 0xAAAAAAAA) >> 1) | ((num & 0x55555555) << 1))
代码分析:
//交换奇偶位,需要先分别拿出奇偶位。
//既然是宏,分别拿出用循环不是很现实,
//那就用& 这些位的方式来做。奇数位拿出,
//那就是要& 上010101010101……,偶数位拿出,
//就是要& 上101010101010……,对应十六进制分别是555……和aaa……,
//一般我们默认是32位整数,4位对应一位16进制就是8个5,8个a。
//通过 & 0x55555555的方式拿出奇数位和 & 0xaaaaaaa的方式拿出偶数位。
//奇数位左移一位就到了偶数位上,偶数位右移一位就到了奇数位上,
//最后两个数字或起来,就完成了交换
完
总结
以上是本文的全部内容, 如果觉得有帮助还望点赞收藏, 如有错误恳请指正