c语言的一些技巧

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值