C语言中一个分号的奇迹(预处理、指针、结构体、内存分配)——一段暗藏玄机的代码
“看热闹”只能是置身事外!
文 章 导 读
今天给大家拼凑一个超经典的程序实例,从这个实例中大家能体会到C语言的玄妙,小伙伴们一定要自己撸一撸代码好好替换哈,希望对大家有所帮助哈,!
看看下面的代码?你见过吗?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
;
;
;
;
printf("\n我运行到这啦哈!!!\n");
return 0;
}
说实在的上面的代码,你确实是见不到的,并不是它有什么问题,而是,你用得时候只有将形式影藏起来才能见到它的威力。
上面代码的运行结果如下:
从上面的结果中我们可以得出一个结论和两个推测。
结论:C语言中支持由单个分号构成的语句。
推测1:单独的分号语句,在编译的时候可能会被编译器优化掉,而不占用空间和运行速度。
推测2:单独的分号语句,没有被编译器优化掉,它可能占空间,也可能占运行速度。
上面的推测没有经过验证,所以我在这里并不能下结论,如果感兴趣,小伙伴们可以去测试一下。
我写上面那段代码的目的,不是为了唬人,而是想说,这个单独的分号语句,也是很有用处的,它结合预处理(这里主要用到宏定义+分支)、指针、结构体、内存分配会发挥意想不到的效果。
重要提醒:下面的代码不长,但能让你get到n多个具有深度的知识点。
大家在看我下面的实例代码的时候,要注意下面4个点,只有将这4个点看到心里有数,才算领会到了实例代码的精髓。
1)宏开关的位置
可以有一个开关,统一动作,也可以将一个开关放到多个位置。
2)利用宏开关,批量开启关闭功能块
可以将不同功能的模块或这说函数等放到一起,用宏开关开启关闭相应的功能。
3)给结构体指针变量和结构体内部的指针变量分配空间
凡是指针都要指向特定的位置,不然就是空指针,也容易造成野指针,造成程序崩溃,很多时候不分配空间直接使用都会报错的。
4)利用宏替换,将函数调用失效
用宏替换将函数名及括号参数替换为空格,函数就是失效了,函数调用不用时都不用注释。
5)在主函数中只是调用,可不可以去掉宏分支
当只是将函数失效,没有变量操作时,宏分支是可以去掉的,这个点大家自己去尝试吧!
代码分为三个函数,主要目的是模块化,名字起得比较随意大家多担待,看内容吧。
1)struct_test.h
#ifndef STRUCT_TEST_H
#define STRUCT_TEST_H
#endif
#define OPERATIN_ON
#ifdef OPERATIN_ON
// 定义两个结构
typedef struct _with_para
{
int p;
int w_val1;
int w_val2;
}with_para_t;
typedef struct _without_para
{
with_para_t *wp;
int stu_val1;
int stu_val2;
}without_para_t;
// 定义结构体变量及指针
without_para_t test_para;
with_para_t with_test;
without_para_t *pp;
// 函数声明
int test_fun1(void);
int test_fun2(int val1,int val2);
#else //将两个函数替换为空格,函数调用处只剩分号,即可取消函数调用
#define test_fun1(void)
#define test_fun2(val1,val2)
#endif
2)struct_test.c
#include<stdio.h>
#include<stdlib.h>
#include"struct_test.h"
#ifdef OPERATIN_ON //此宏没定义,下面的函数定义就失效了,不用注释定义和调用就可以用宏批量取消掉某种功能的函数
// 此函数适合用于初始化,初始值用结构指定,并返回给结构中的指针变量
int test_fun1(void)
{
with_test.p = 3;
with_test.w_val1 = 4;
with_test.w_val2 = 5;
}
// 此函数适合带参初始化
int test_fun2(int val1,int val2)
{
pp->stu_val1 = val1;
pp->stu_val2 = val2;
pp->wp = &with_test;
}
#endif
3)main.c
#include <stdio.h>
#include <stdlib.h>
#include"struct_test.h"
#ifdef OPERATIN_ON
// 声明外部结构变量
extern without_para_t test_para;
extern with_para_t with_test;
extern without_para_t *pp;
#endif
int main(int argc, char *argv[])
{
#ifdef OPERATIN_ON // 宏定义起作用的分支
printf("宏开启啦!\n");
// 指向结构的指针需要分配空间,结构中的指针也要分配空间
test_para.wp = (with_para_t *)malloc(sizeof(with_para_t));
pp = (without_para_t *)malloc(sizeof(without_para_t));
// 函数起作用
test_fun1();
test_fun2(1,2);
// 打印信息
printf("\n打印函数信息如下:\n\n");
printf("pp->stu_val1 = %d\n",pp->stu_val1);
printf("pp->stu_val2 = %d\n",pp->stu_val2);
printf("pp->wp->p = %d\n",pp->wp->p);
#else //将宏定义OPERATIN_ON注释掉,宏失效运行此分支, test_fun1();被替换为;,即不再调用这两个函数。
printf("宏关闭啦!\n");
// 函数调用被替换为分号,函数失效
printf("\n函数调用被替换为分号,失去调用意义啦!\n");
test_fun1();
test_fun2(1,2);
#endif
printf("\n我运行到这啦哈!!!\n");
return 0;
}
当宏OPERATIN_ON打开(定义)时,运行结果如下:
当宏OPERATIN_ON关闭(注释)时,运行结果如下:
提示:上面的代码,大家可以建立一个工程去试试,只是看是不太好体到它的应用价值的。
宏替换不仅可以换函数,还可以换变量是否复制,相关内容请看我的另一篇文章——。
总结
今天这篇文章是时分实用的,这里只是抛砖引玉,并没有结合实际的应用,但小伙伴们还是会有不小的收获的,要自己把代码拿下来撸一撸哈,看热闹只能是置身事外哈,小伙伴们敬请期待哈,。
相关文章:
专辑推荐: