【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语言】那些优秀代码里的骚操作(持续更新…)相关推荐

  1. 逆向趣事:那些封印在代码中的骚操作

    在逆向一些正常或恶意软件时,有时会遇到一些作者封印在代码中的骚操作,有趣又另类,甚至可以作为检测规则来应用,今天就来聊聊这些骚操作. 01 - 闲趣型 2012年的时候,Fireye捕获到一个Java ...

  2. 直接输出代码_C语言入门 | 优秀代码(四)A—F

    文章内容摘自简书,仅供学习参考使用. A : 找好人 题目描述: 某学校有四位同学中的一位做了好事,不留名,表扬信来了之后,校长问这四位是谁做的好事.四个人的回答分别是: A说:不是我 B说:是C C ...

  3. python switch语句_几个Python里的骚操作

    今天给大家分享几个Python里面的骚操作,大家会更加感受到Python编码的强大. 1.用字典映射代替switch case语句 大家首先看下面这段用C#编写的switch case代码,代码很好理 ...

  4. 闪电侠 Netty 小册里的骚操作

    前言 即使这是一本小册,但基于"不提笔不读书"的理念,仍然有必要总结一下.此小册对于那些"硬杠 Netty 源码 却不曾在千万级生产环境上使用实操"的用户非常有 ...

  5. 一篇文章畅游在C语言基础知识学习的海洋中(持续更新中……)

    C语言概述 标准C库 ANSI C共包括15个头文件. 1995年,Normative Addendum 1(NA1)批准了3个头文件(iso646.h.wchar.h和wctype.h)增加到C标准 ...

  6. C语言笔记系列文章 索引目录表(持续更新中......)

    前言: 都快大三了,想起大一的时候学C语言,什么都不懂.由于对语言不是很了解,也就没有认真学习.其实C语言在计算机行业中还是比较重要的一门基础课程.虽然现在的开发基本不会用C,但它是母语这是毋庸置疑的 ...

  7. 优秀的Android开源框架(持续更新)

    开源是软件发展的趋势,越来越多的人投入到开源世界中去.我们可以从开源世界中获得很多有益的东西,本着不重复造轮子的精神,我们应该充分利用这些开源项目的成果.本文会持续更新涌现出来的优秀开源框架. UI ...

  8. LeetCode JAVA语言全部解题思路+答案代码+多种解法+关键注释(持续更新...)

    第一题: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组 ...

  9. Java8 - 避免代码阻塞的骚操作

    文章目录 Pre 避免同步阻塞的困扰 V1.0 改进 -采用Stream 顺序查询 (不理想) V2.0 改进 - 使用并行流对请求进行并行操作 (good) V3.0 改进 - 使用 Complet ...

最新文章

  1. type=file的未选择任何文件修改_PDF文件怎样输入到CAD图纸中?懂得这个功能可以快速实现...
  2. 静态网页与动态的区别
  3. SpaceX「十一手」火箭创纪录,一天内两次升空,马斯克:飞100次才退役
  4. 【图解】一图了解《上海市推进新一代信息基础设施建设 助力提升城市能级和核心竞争力三年行动计划(2018-2020年)》...
  5. 神策数据入选 Facebook 全球合作计划,助力出海客户拥抱全球化广告生态
  6. 谷歌又放大招:视觉效果完胜其他SOTA的风格迁移网络,手机端可达实时4K
  7. Levenshtein算法的JavaScript实现
  8. java 返回值 泛型 继承_java泛型类继承问题?
  9. MindSDK+yolov5部署及python版图像视频推理实现
  10. HTML5 Audio/标签Api整理(二)
  11. SAP Cloud for Customer的自动化测试指南
  12. IAR集成开发环境的使用
  13. C#反射Assembly 详细说明
  14. C# WinForm DataGridView 给标题列增加序号及格式化某个字段
  15. JS 数组reduce()方法详解及高级技巧
  16. 远控免杀从入门到实践(2)工具总结篇
  17. 终极解决苹果开发者中心Edit Phone Number
  18. 【Termiology】常见术语的检索
  19. 建议将com.alibaba:fastjson升级至1.2.83
  20. 故事,零落,,,,,

热门文章

  1. python集合怎么表示_Python 集合(Set)、字典(Dictionary)
  2. 换硬币的c语言程序流程图,C语言换分币问题
  3. 微信小程序保姆级入门教程
  4. 电气成套设备行业如何借助ERP系统,解决企业管理难题?
  5. 使用redisson引起的故障:org.redisson.client.RedisException: MOVED redirection loop detected.
  6. 计算机专业考研电路原理,2019电子信息工程考研方向_电路与系统专业解读
  7. 陶哲轩实分析--推荐
  8. 如何批量给照片加水印?详细图文教程
  9. 中国移动苏州研发中心一面
  10. 介绍一下电脑管家小团队VIP版本,限时免费2个月开放体验啦!