偶然发现 CMU 的 wiki,里面有 C/C++ 的编写小技巧和提醒,特意挑了些自以为的重点做了笔记,其中可能还混杂了我在其他地方看到的内容,详细内容 wiki 可以看文末链接。
1、preprocessor
1.1、universal character names
The universal character name \Unnnnnnnn designates the character whose 8-digit short identifier (as specified by ISO/IEC 10646) is nnnnnnnn.
Similarly, the universal character name \unnnn designates the character whose 4-digit short identifier is nnnn (and whose 8-digit short identifier is 0000nnnn).
1.2、#include_next
例如有个搜索路径链,在#include中,它们的搜索顺序依次是A,B,C,D和E。在B目录中有个头文件叫a.h,在D目录中也有个头文件叫a.h,如果在我们的源代码中这样写#include <a.h>,那么我们就会包含的是B目录中的a.h头文件,如果我们这样写#include_next <a.h>那么我们就会包含的是D目录中的a.h头文件。#include_next <a.h>的意思按我们上面的引号包含中的解释来说就是“在B目录中的a.h头文件后面的目录路径(即C,D和E)中搜索a.h头文件并包含进来)。#include_next <a.h>的操作会是这样的,它将在A,B,C,D和E目录中依次搜索a.h头文件,那么首先它会在B目录中搜索到a.h头文件,那它就会以B目录作为分割点,搜索B目录后面的目录(C,D和E),然后在这后面的目录中搜索a.h头文件,并把在这之后搜索到的a.h头文件包含进来。这样说的话大家应该清楚了吧。
还有一点是#include_next是不区分<>和""的包含形式的。
现在来说说为什么要引人这条指令!
假如,你要创建一个新的头文件,而这个新的头文件和现在已有的头文件有相同的名字,而且你想用你的这个新的头文件,那么你要做的就是把这个新的头文件放在#include指令的搜索路径的前面,即是在旧的头文件的前面新的头文件首先被搜索到,这样你就可以使用你这个新的头文件。但是你在另一个源代码文件中想使用旧的头文件了,那怎么办!有个办法就是使用绝对路径来搜索,那么就不存在这样的问题了。问题出在,如果我们把头文件的位置移动了,移到了其它的目录里了,那我们就得在相应的源码文件中修改这个包含的绝对路径,如果一个源码文件还好,但如果是大型工程的话,修改的地方多了就容易出问题。
1.3、macro side effects
#define ABS(x) (((x) < 0) ? -(x) : (x))
int m = ABS(++n);
// equal to below
m = (((++n) < 0) ? -(++n) : (++n));
// how to avoid
++n;
int m = ABS(n);
// or prefer inline or static functions to function-like macros
// Inline substitution is not textual substitution, nor does it create a new function.
static inline int iabs(int x) {
return (((x) < 0) ? -(x) : (x));
}
// GCC's __typeof extension makes it possible to
// declare and assign the value of the macro operand to a temporary of the same type
// and perform the computation on the temporary,
// consequently guaranteeing that the operand will be evaluated exactly once.
#define ABS(x) __extension__ ({ __typeof (x) tmp = x; \
tmp < 0 ? -tmp : tmp; })
Expressions used as arguments to the standard assert() macro should not have side effects.
1.4、STDC_VERSION
Checks __STDC_VERSION__ to ensure that a pre-C11 compiler will fail to compile the code, rather than invoking undefined behavior.
#if __STDC_VERSION__ < 201112L
#error This code requires a compiler supporting the C11 standard or newer
#endif
2、tips
2.1、memset
int buff_2[10];
memset(buff_2,1,sizeof(buff_2));
for(int i = 0;i<10;i++)
{
printf("%d ",buff_2[i]);
}
是的,变量的类型变了,打印的结果是:
16843009

本文整理了CMU wiki中C/C++编写的小技巧和提醒。涵盖预处理器相关内容,如通用字符名、#include_next指令等;还介绍了memset使用、指针判断、结构体字节对齐等实用技巧;最后提及C++ 11及之后的单例模式和多值返回获取。
最低0.47元/天 解锁文章
1735





