c语言的一些技巧

来源:互联网 发布:少儿编程入门教程 编辑:程序博客网 时间:2024/05/16 06:07
1  有一个鲜为人知的运算符叫”趋向于”, 写作“-->”。比如说如果要实现一个倒数的程序,我们可以定义一个变量x,然后让它趋向于0...
C++有另一个更鲜为人知的运算符叫做“快速趋向于”,比如同样是从10到0,这里这么写
#include <stdio.h>int main(void){    int x = 10;    while (0 <---- x) {        printf("%d ", x);    }    return 0;}
会打印出:
8 6 4 2


作者:Geek An
链接:https://www.zhihu.com/question/27417946/answer/36617347
来源:知乎
 2  以下等式皆成立:
a[5] == 5[a];"ABCD"[2] == 2["ABCD"] == 'C';
因为C语言的底层都是指针,数组的实现也是。对于compiler来说,它们木有区别:
*(a + 5) == *(5 + a)
下面这个打印是否让你惊奇?
#include <stdio.h>int main(void){    int x = 5;    printf("%d and ", sizeof(x++)); // note 1    printf("%d\n", x); // note 2    return 0;}
它会打印出:
4 and 5
因为 sizeof 是编译时行为,运行时不会执行


作者:Geek An
链接:https://www.zhihu.com/question/27417946/answer/36617347
来源:知乎
3 代码来自参与过的开源工程ovs,OpenFlow的业界标杆)
#define OFPACTS                                                         \    /* Output. */                                                       \    OFPACT(OUTPUT,          ofpact_output,      ofpact, "output")       \    OFPACT(GROUP,           ofpact_group,       ofpact, "group")#define OFPACT(ENUM, STRUCT, MEMBER, NAME)                              \    BUILD_ASSERT_DECL(offsetof(struct STRUCT, ofpact) == 0);            \                                                                        \    enum { OFPACT_##ENUM##_RAW_SIZE                                     \           = (offsetof(struct STRUCT, MEMBER)                           \              ? offsetof(struct STRUCT, MEMBER)                         \              : sizeof(struct STRUCT)) };                               \                                                                        \    static inline struct STRUCT *                                       \    ofpact_get_##ENUM(const struct ofpact *ofpact)                      \    {                                                                   \        ovs_assert(ofpact->type == OFPACT_##ENUM);                      \        return ALIGNED_CAST(struct STRUCT *, ofpact);                   \    }OFPACTS#undef OFPACT
看懂以上代码的功能了吗?它定义了一些字段,然后再通过宏来批量生成函数和enum,狂拽酷炫!
学名叫做x macro,是节省冗余代码利器,好处是非常好用,跟机关枪一样;坏处是懂的人不多,大家看到一个没有被索引的ofpact_get_GROUP很容易就进入痴呆状态。
完整版的黑魔法五可以点这里 cowry/x_macro.c at master · geekan/cowry · GitHub
4
C语言还有另一个更加鲜为人知的运算符,叫做蝌蚪运算符(tadpole operator),用于实现单目的加一、减一运算。

语法     含义     助记-~y      y + 1   蝌蚪游向一个值让它变大~-y      y - 1   蝌蚪离开一个值让它变小

有了这两个运算符,我们可以改写如下的代码
x = (y + 1) % 10;x = (y + 1) * (z - 1);x = (double)(f(y) + 1);
变为
x = -~y % 10;x = -~y * ~-z;x = (double)-~f(y);
减少了括号的使用,使代码更简单。

-----------


作者:武振伟
链接:https://www.zhihu.com/question/27417946/answer/49040520
来源:知乎
6
作者:justjavac
链接:https://www.zhihu.com/question/27417946/answer/36585519
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

摘自《C专家编程》 (如果你正在学习C/C++,建议你多读几遍这本书。网上有电子版,我就不给链接了。)

根据位模式构建图形图标(icon)或者图形(glyph),是一种小型的位模式映射于屏幕产生的图像。一个位代表图像上的一个像素。如果一个位被设置,那么它所代表的像素就是“亮”的。如果一个位被清除,那么它所代表的像素就是“暗”的。所以,一系列的整数值能够用于为图像编码。


类似Iconedit这样的工具就是用于绘图的,他们所输出的是一个包含一系列整型数的ASCII文件,可以被一个窗口程序所包含。它所存在的问题是程序中的图标只是一串十六进制数。


在C语言中,典型的16X16的黑白图形可能如下:

static unsigned short stopwatch[] = {0x07C6,0x1FF7,0x383B,0x600C,0x600C,0xC006,0xC006,0xDF06,0xC106,0xC106,0x610C,0x610C,0x3838,0x1FF0,0x07C0,0x0000};

正如所看到的那样,这些C语言常量并未有提供有关图形实际模样的任何线索。

这里有一个惊人的#define定义的优雅集合,允许程序建立常量使它们看上去像是屏幕上的图形。

#define X )*2+1#define _ )*2#define s ((((((((((((((((0 /* For building glyphs 16 bits wide */

定义了它们之后,只要画所需要的图标或者图形等,程序会自动创建它们的十六进制模式。使用这些宏定义,程序的自描述能力大大加强,上面这个例子可以转变为:

static unsigned short stopwatch[] ={s _ _ _ _ _ X X X X X _ _ _ X X _ ,s _ _ _ X X X X X X X X X _ X X X ,s _ _ X X X _ _ _ _ _ X X X _ X X ,s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,s X X _ X X X X X _ _ _ _ _ X X _ ,s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,s _ _ X X X _ _ _ _ _ X X X _ _ _ ,s _ _ _ X X X X X X X X X _ _ _ _ ,s _ _ _ _ _ X X X X X _ _ _ _ _ _ ,s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _};

显然,与前面的代码相比,它的意思更为明显。标准的C语言具有八进制、十进制和十六进制常量,但没有二进制常量,否则的话倒是一种更为简单的绘制图形模式的方法。

7
作者:Shanicky
链接:https://www.zhihu.com/question/27417946/answer/36583624
来源:知乎

当你需要将错误码对应到错误信息时
/* Entries may not correspond to actual numbers. Some entries omitted. */#define EINVAL 1#define ENOMEM 2#define EFAULT 3/* ... */#define E2BIG  7#define EBUSY  8/* ... */#define ECHILD 12/* ... */
你可以使用
char *err_strings[] = {      [0] = "Success",[EINVAL] = "Invalid argument",[ENOMEM] = "Not enough memory",[EFAULT] = "Bad address",/* ... */[E2BIG ] = "Argument list too long",[EBUSY ] = "Device or resource busy",/* ... */[ECHILD] = "No child processes"/* ... */};
这样的代码初始化 err_strings时,指定的元素会被初始化为对应的字符串,其余元素默认初始化为0
8
作者:we1we1
链接:https://www.zhihu.com/question/27417946/answer/36627464
来源:知乎

不知道这个「奇技淫巧」是怎么定义的,但在用C设计模块接口的时候,有很多非常实用小tricks还是值得提一下的。
...
Redis里的sds(简易动态字符串库)
struct sdshdr {    int len;    int free;    char buf[];};
sds sdsnewlen(const void *init, size_t initlen) {    struct sdshdr *sh;    if (init) {        sh = zmalloc(sizeof(struct sdshdr)+initlen+1);    } else {        sh = zcalloc(sizeof(struct sdshdr)+initlen+1);    }    if (sh == NULL) return NULL;    sh->len = initlen;    sh->free = 0;    if (initlen && init)        memcpy(sh->buf, init, initlen);    sh->buf[initlen] = '\0';    return (char*)sh->buf;  //返回了char *}
而新申请的sds返回了char *,而不是struct sdshdr *。直接使用的也是char *。这样做的目的是为了兼容一些类似strcmp、strcat的库函数。
而要使用到sds的信息时,只需要将字符串地址减去sds的大小就可以的到sds的地址。
例如:
static inline size_t sdslen(const sds s) {    struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr))); //获取sds的地址    return sh->len; //返回长度}

0 0
原创粉丝点击