【C语言】那些优秀代码里的骚操作(持续更新…)
【C语言】那些优秀代码里的骚操作(持续更新…)
- 1、联合体`union`的妙用
- 2、`#include`的本质是什么?
- 3、脱裤子放屁的`do{ }while(0)`
- 4、一个成熟的代码要学会自己写函数
- 5、……
语言这个东西,其实没有奇技淫巧,凡是可以写出来的,能被编译器识别的,都是常规操作,这里所谓的骚操作,其实是想说那些看起来不合理,但是自有道理的写法。这些写法大都是对C语言本质理解不透彻导致的惊奇。然而,我们应该保持惊奇, 纪德说:“智者,乃是对一切都发生惊奇的人。”
很多奇怪的写法,大多是我看一些SDK、库、框架时见到过的,这些操作也许你见到过,也许会说:哦,就这?那么恭喜你,这个逼我不装了,让你来。
这篇文章,想起来就就会来更新一下……
1、联合体union
的妙用
假设有以下字节流数据date
(共6Byte长度):
字节 | 1Byte | 1Byte | 1Byte | 1Byte | 1Byte | 1Byte |
---|---|---|---|---|---|---|
含义 | 年 | 月 | 日 | 时 | 分 | 秒 |
如果我们要分别解析出每一字节,我们一般会采用移位操作,但代码复杂
如果我们这样写:
typedef struct time_s {char year;char mouth;char day;char hour;char min;char sec;
}time_t;union time {time_t t;char date[6];
};void get_time() {union time time_u;//这个例子有点像银行存钱时 整存零取 的模式memcpy(&time_u.date, "12345",6);//整存printf("the hour is:%c", time_u.t.hour);//零取
}
则将输出
the hour is:4
这就充分利用了联合体共享内存的特性。
2、#include
的本质是什么?
看到这个题目,有人会说:当然是包含头文件
不,这只是一个现象,不是本质,它的本质是展开所包含文件的代码。
这是有一天看LWIP源码恍然大悟的:
typedef enum
{#include LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,
#include "lwip/priv/memp_std.h"MEMP_MAX
} memp_t;
这段代码经过编译器处理后是这样的:
typedef enum
{ MEMP_RAW_PCB,MEMP_UDP_PCB,MEMP_TCP_PCB,MEMP_MAX
}
那memp_std.h
中放了什么呢?
LWIP_MEMPOOL(RAW, MEMP_NUM_RAW_PCB ,sizeof(struct raw_pcb), "raw_pcb")
LWIP_MEMPOOL(UDP, MEMP_NUM_UDP_PCB ,sizeof(struct udp_pcb), "udp_pcb")
LWIP_MEMPOOL(TCP, MEMP_NUM_TCP_PCB ,sizeof(struct tcp_pcb), "tcp_pcb")
所以,头文件里放的东西不一定是一些变量、函数的声明,只要把它展开,放在被引用处的上下文能编译通过,那就可以随便你写什么!那么我们倒过来想:是不是我们也可以把原来.c中的一段代码截取出来放到.h中,然后在此处用#inlcude ".h"
取而代之?当然可以!那么这么做有什么好处呢?比如说,我们想把.c的一段代码单独拎出来提供给其他层使用,当然了,大部分时候,这些内容是那些我们常见的函数和变量,但是记住:那些.h中未声明的东西我们依然可以在.h中使用,因为它们可能在.c中展开之后就语义通顺了。
另外注意,#include不是.h的专属,也可以是txt。
3、脱裤子放屁的do{ }while(0)
上一次看到do{ }while(0)
还是在上一次,它的一个主要作用就是限制作用域,这也是C语言中{}
的作用。有些人喜欢拿宏展开举例子,来证明do{ }while(0)
可以限制代码的作用域,避免宏展开后与上下文结合产生新的语义,但这{}
也可以做到。
①先来说说这个限制作用域的问题:
void print()
{cout<<"print: "<<endl;
}
void send()
{cout <<"send: "<<endl;
}#define LOG print();send();int main(){if (false)LOGsystem("pause");return 0;
}
这种情况这样写:#define LOG { print();send(); }
,也可以解决啊,do{ }while(0)
纯粹是脱裤子放屁
但是如果这样调用宏:
if (false)LOG;
else{}
使用{}
来限制作用域,展开后则为:
if (false)
{print();send();
};
else{}
便会报错。
使用do{ }while(0)
来限制作用域,展开后则为:
if (false)
do{print();send();
}while(0);
else{}
这才是do{ }while(0)
的优势。
②还有种说法,do{ }while(0)
还可以和break
搭配使用,以代替goto
语句,优点就是break即使漏写,也会跳出执行后面的语句;goto END;
漏写便执行不到END:
后的语句,我认为是无稽之谈,这也漏写,那也漏写,别编程了。这和①情况完全不同,①中的宏可能是由其他层提供的,层间存在不确定性,goto不存在这个问题。可以这样写,但别说什么代替goto,goto没惹你,告诉你特性了,你自己不注意是你的问题。这仅代表我此时码字的心情,明天我可能就不这么说了,不喜勿喷。
4、一个成熟的代码要学会自己写函数
这是一段来自某厂商SDK的shell交互代码,用宏来生成函数,有C基础的人一看便知:
#define CLI_CMD(name, help, func) \int _cli_inter_##func (char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) \{ \int argc = 0; \char *argv[CLI_MAX_ARGS]; \argc = CLITokenizeCommand(pcCommandString, argv); \return func(argc, argv); \} \__attribute__((__used__)) const CLI_Command_Definition_t _cli_cmd_##func __SECTION(".commands") = \{ name, help, _cli_inter_##func }
但不要忘了使用__attribute__((__used__))
,向编译器说明这段代码有用,即使在没有用到的情况下编译器也不会警告!
5、……
【C语言】那些优秀代码里的骚操作(持续更新…)相关推荐
- 逆向趣事:那些封印在代码中的骚操作
在逆向一些正常或恶意软件时,有时会遇到一些作者封印在代码中的骚操作,有趣又另类,甚至可以作为检测规则来应用,今天就来聊聊这些骚操作. 01 - 闲趣型 2012年的时候,Fireye捕获到一个Java ...
- 直接输出代码_C语言入门 | 优秀代码(四)A—F
文章内容摘自简书,仅供学习参考使用. A : 找好人 题目描述: 某学校有四位同学中的一位做了好事,不留名,表扬信来了之后,校长问这四位是谁做的好事.四个人的回答分别是: A说:不是我 B说:是C C ...
- python switch语句_几个Python里的骚操作
今天给大家分享几个Python里面的骚操作,大家会更加感受到Python编码的强大. 1.用字典映射代替switch case语句 大家首先看下面这段用C#编写的switch case代码,代码很好理 ...
- 闪电侠 Netty 小册里的骚操作
前言 即使这是一本小册,但基于"不提笔不读书"的理念,仍然有必要总结一下.此小册对于那些"硬杠 Netty 源码 却不曾在千万级生产环境上使用实操"的用户非常有 ...
- 一篇文章畅游在C语言基础知识学习的海洋中(持续更新中……)
C语言概述 标准C库 ANSI C共包括15个头文件. 1995年,Normative Addendum 1(NA1)批准了3个头文件(iso646.h.wchar.h和wctype.h)增加到C标准 ...
- C语言笔记系列文章 索引目录表(持续更新中......)
前言: 都快大三了,想起大一的时候学C语言,什么都不懂.由于对语言不是很了解,也就没有认真学习.其实C语言在计算机行业中还是比较重要的一门基础课程.虽然现在的开发基本不会用C,但它是母语这是毋庸置疑的 ...
- 优秀的Android开源框架(持续更新)
开源是软件发展的趋势,越来越多的人投入到开源世界中去.我们可以从开源世界中获得很多有益的东西,本着不重复造轮子的精神,我们应该充分利用这些开源项目的成果.本文会持续更新涌现出来的优秀开源框架. UI ...
- LeetCode JAVA语言全部解题思路+答案代码+多种解法+关键注释(持续更新...)
第一题: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组 ...
- Java8 - 避免代码阻塞的骚操作
文章目录 Pre 避免同步阻塞的困扰 V1.0 改进 -采用Stream 顺序查询 (不理想) V2.0 改进 - 使用并行流对请求进行并行操作 (good) V3.0 改进 - 使用 Complet ...
最新文章
- type=file的未选择任何文件修改_PDF文件怎样输入到CAD图纸中?懂得这个功能可以快速实现...
- 静态网页与动态的区别
- SpaceX「十一手」火箭创纪录,一天内两次升空,马斯克:飞100次才退役
- 【图解】一图了解《上海市推进新一代信息基础设施建设 助力提升城市能级和核心竞争力三年行动计划(2018-2020年)》...
- 神策数据入选 Facebook 全球合作计划,助力出海客户拥抱全球化广告生态
- 谷歌又放大招:视觉效果完胜其他SOTA的风格迁移网络,手机端可达实时4K
- Levenshtein算法的JavaScript实现
- java 返回值 泛型 继承_java泛型类继承问题?
- MindSDK+yolov5部署及python版图像视频推理实现
- HTML5 Audio/标签Api整理(二)
- SAP Cloud for Customer的自动化测试指南
- IAR集成开发环境的使用
- C#反射Assembly 详细说明
- C# WinForm DataGridView 给标题列增加序号及格式化某个字段
- JS 数组reduce()方法详解及高级技巧
- 远控免杀从入门到实践(2)工具总结篇
- 终极解决苹果开发者中心Edit Phone Number
- 【Termiology】常见术语的检索
- 建议将com.alibaba:fastjson升级至1.2.83
- 故事,零落,,,,,
热门文章
- python集合怎么表示_Python 集合(Set)、字典(Dictionary)
- 换硬币的c语言程序流程图,C语言换分币问题
- 微信小程序保姆级入门教程
- 电气成套设备行业如何借助ERP系统,解决企业管理难题?
- 使用redisson引起的故障:org.redisson.client.RedisException: MOVED redirection loop detected.
- 计算机专业考研电路原理,2019电子信息工程考研方向_电路与系统专业解读
- 陶哲轩实分析--推荐
- 如何批量给照片加水印?详细图文教程
- 中国移动苏州研发中心一面
- 介绍一下电脑管家小团队VIP版本,限时免费2个月开放体验啦!