刚发现一个C语言语法糖

公子骏 2011-08-21 06:33:30

#include <stdio.h>

#define array_each(arr, type, pos, val, code) {\
type *_arr = (arr);\
unsigned int i, _len = sizeof(arr) / sizeof(type);\
type val;\
for (pos = 0; pos < _len; pos++) {\
val = _arr[pos];\
code;\
}\
}

int main (char argc, char **argv)
{
int arrt[] = {1, 3, 5, 6, 90, 32, 64};
array_each(arrt, int, i, v,
printf("%d: %s\n", i, v);
);
}


我想同理也因该能实现 array_map
...全文
2213 50 打赏 收藏 转发到动态 举报
写回复
用AI写文章
50 条回复
切换为时间正序
请发表友善的回复…
发表回复
Heartwork 2011-08-24
  • 打赏
  • 举报
回复
1. 可以使用typeof关键字获取arr的类型,这样就不用传int做为这个宏的参数了。

2. stl的for_each效率未必比这个差。
// sgi stl 3.3的实现:
// 实现在头文件中的模板函数,实际调用时会inline展开,免去了函数调用的开销,缺点是对于不同的模板参数类型会引起代码膨胀。针对lz的这个例子不存在这个问题。
template <class _InputIter, class _Function>
// 两个传值的iterator,效率取决于传入的iterator类型,若原生指针则和C等价。
// lz的例子里使用的printf需要使用function object封装一下,效率是没问题,但是由于这个function object的类型为unary function,所以和lz所说的情形不同:)
_Function for_each(_InputIter __first, _InputIter __last, _Function __f) {
// 在编译器检查模板参数类型是否满足input iterator requirement的宏,不满足的话编译器会报错。因为在该宏内部执行的函数与其他代码关联,所以编译时该段代码会被删除,不会影响执行效率。lz传入的指针属于random iterator,满足条件。
__STL_REQUIRES(_InputIter, _InputIterator);
// 针对iterator的++和!=的效率依赖具体类型,原生指针效率与C等价。
for ( ; __first != __last; ++__first)
__f(*__first);
// 唯一会引起效率损失的位置,针对x86平台会多执行一个mov指令。
// 但是因为该函数会inline在代码中,所以若该返回值没有被使用的话,可以被编译器优化掉。(有可能需要打开优化选项。
return __f;
}

口说无评,上代码:
test.cpp
#include <stdio.h>
#include <algorithm>

struct print {
void operator () (int val) {
printf("val = %d\n", val);
}
};

int main (int argc, char **argv)
{
int arrt[] = {1, 3, 5, 6, 90, 32, 64};
std::for_each(arrt, arrt + sizeof(arrt) / sizeof(arrt[0]), print());

return 0;
}

打开-03选项后objdump出来的asm code,本人用的cygwin的环境。

00401180 <main>:
# 设置环境堆栈
401180: 8d 4c 24 04 lea 0x4(%esp),%ecx
401184: 83 e4 f0 and $0xfffffff0,%esp
401187: ff 71 fc pushl -0x4(%ecx)
40118a: 55 push %ebp
40118b: 89 e5 mov %esp,%ebp
40118d: 51 push %ecx
40118e: 83 ec 34 sub $0x34,%esp
401191: e8 5a 01 00 00 call 4012f0 <__main>
# 初始化数组arrt
401196: c7 45 e0 01 00 00 00 movl $0x1,-0x20(%ebp)
40119d: c7 45 e4 03 00 00 00 movl $0x3,-0x1c(%ebp)
4011a4: c7 45 e8 05 00 00 00 movl $0x5,-0x18(%ebp)
4011ab: c7 45 ec 06 00 00 00 movl $0x6,-0x14(%ebp)
4011b2: c7 45 f0 5a 00 00 00 movl $0x5a,-0x10(%ebp)
4011b9: c7 45 f4 20 00 00 00 movl $0x20,-0xc(%ebp)
4011c0: c7 45 f8 40 00 00 00 movl $0x40,-0x8(%ebp)
# 通过下面的代码可以看到,for_each函数做了inine处理,__STL_REQUIRES的requirement检查,print()临时对象也已经优化掉了。同时,因为这个数组比较小,所以将循环展开了。

# 将第一个值1放到堆栈中
4011c7: c7 44 24 04 01 00 00 movl $0x1,0x4(%esp)
4011ce: 00
# 将字符串“val = %d”地址放到堆栈中
4011cf: c7 04 24 a0 20 40 00 movl $0x4020a0,(%esp)
4011d6: e8 1d 01 00 00 call 4012f8 <printf>
# 以下同上。
4011db: 8b 45 e4 mov -0x1c(%ebp),%eax
4011de: c7 04 24 a0 20 40 00 movl $0x4020a0,(%esp)
4011e5: 89 44 24 04 mov %eax,0x4(%esp)
4011e9: e8 0a 01 00 00 call 4012f8 <printf>
4011ee: 8b 45 e8 mov -0x18(%ebp),%eax
4011f1: c7 04 24 a0 20 40 00 movl $0x4020a0,(%esp)
4011f8: 89 44 24 04 mov %eax,0x4(%esp)
4011fc: e8 f7 00 00 00 call 4012f8 <printf>
401201: 8b 45 ec mov -0x14(%ebp),%eax
401204: c7 04 24 a0 20 40 00 movl $0x4020a0,(%esp)
40120b: 89 44 24 04 mov %eax,0x4(%esp)
40120f: e8 e4 00 00 00 call 4012f8 <printf>
401214: 8b 45 f0 mov -0x10(%ebp),%eax
401217: c7 04 24 a0 20 40 00 movl $0x4020a0,(%esp)
40121e: 89 44 24 04 mov %eax,0x4(%esp)
401222: e8 d1 00 00 00 call 4012f8 <printf>
401227: 8b 45 f4 mov -0xc(%ebp),%eax
40122a: c7 04 24 a0 20 40 00 movl $0x4020a0,(%esp)
401231: 89 44 24 04 mov %eax,0x4(%esp)
401235: e8 be 00 00 00 call 4012f8 <printf>
40123a: c7 44 24 04 40 00 00 movl $0x40,0x4(%esp)
401241: 00
401242: c7 04 24 a0 20 40 00 movl $0x4020a0,(%esp)
401249: e8 aa 00 00 00 call 4012f8 <printf>
# 堆栈恢复,很奇怪它为什么要预留这么大的空间。
40124e: 83 c4 34 add $0x34,%esp
401251: 31 c0 xor %eax,%eax
401253: 59 pop %ecx
401254: 5d pop %ebp
401255: 8d 61 fc lea -0x4(%ecx),%esp
401258: c3 ret
401259: 90 nop
40125a: 90 nop
40125b: 90 nop
40125c: 90 nop
40125d: 90 nop
40125e: 90 nop
40125f: 90 nop
icesai 2011-08-24
  • 打赏
  • 举报
回复
同求语法糖 嘿嘿
kkrmr 2011-08-24
  • 打赏
  • 举报
回复
语法糖??我要百度了!!
贪食蛇男 2011-08-24
  • 打赏
  • 举报
回复
[Quote=引用 44 楼 kwer 的回复:]

引用 43 楼 hiroyukki 的回复:
我一般不用比较大的宏,调试起来麻烦
8楼所提到的Linux代码算不算比较大的宏呢?
[/Quote]
小宏,用着方便。
还有比如 offsetof 宏,用着舒心啊。
当然,大宏用着也方便,比如MFC的宏。
但是宏比较长的话,调试就比较恶心了。

像这种宏:

#define PROCESSFILENAME() \
WPATH desPath = {0}; \
wcscat(desPath, foi->destFolder); \
unsigned int len = wcslen(foi->srcList[i]); \
while(foi->srcList[i][--len] != L'\\' && len >= 0); \
wcscat(desPath, foi->srcList[i] + len); \
DWORD attrb = GetFileAttributesW(desPath); \
if(INVALID_FILE_ATTRIBUTES == attrb) \
{ \
continue; \
} \

纯粹是为了减少几次重复写代码,用着爽归爽,如果有BUG,调试起来也比较恶心了。
kwer 2011-08-24
  • 打赏
  • 举报
回复
[Quote=引用 43 楼 hiroyukki 的回复:]
我一般不用比较大的宏,调试起来麻烦
[/Quote]8楼所提到的Linux代码算不算比较大的宏呢?
贪食蛇男 2011-08-24
  • 打赏
  • 举报
回复
我一般不用比较大的宏,调试起来麻烦
kwer 2011-08-24
  • 打赏
  • 举报
回复
这不就是C++模板的C语言版本吗?
ralf 2011-08-24
  • 打赏
  • 举报
回复
谢谢分享, 我也是在Lua和IO-lang源码里看到各种舒服的写法,
固拿出一条来晒晒,也想自己在其他用处方面推广一下。
sanae 2011-08-24
  • 打赏
  • 举报
回复
接LS:

如果能在代码回顾中发现的问题 就不要留到编译时发现
编译时能发现的问题 就不要留到运行时发现
运行时能发现的问题 就不要留到调试时发现……
sanae 2011-08-24
  • 打赏
  • 举报
回复
[Quote=引用 45 楼 hiroyukki 的回复:]

引用 44 楼 kwer 的回复:

引用 43 楼 hiroyukki 的回复:
我一般不用比较大的宏,调试起来麻烦
8楼所提到的Linux代码算不算比较大的宏呢?

小宏,用着方便。
还有比如 offsetof 宏,用着舒心啊。
当然,大宏用着也方便,比如MFC的宏。
但是宏比较长的话,调试就比较恶心了。

像这种宏:
C/C++ code

#define PRO……
[/Quote]


其实个人偷偷认为assert和static_assert还是不能少的
在宏里面被展开也好
在代码里面也好
等到出问题了一句句单步调试,对我自己来说的话,效率有点低,呵呵,这个倒是因人而异

缘来是妳 2011-08-24
  • 打赏
  • 举报
回复
弱弱的问句,语法糖什么意思?
CJacky++ 2011-08-24
  • 打赏
  • 举报
回复
学习了。
meaningness 2011-08-24
  • 打赏
  • 举报
回复
这种东西linux内核里不是满大街都是吗
cp298674954 2011-08-23
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 jackyjkchen 的回复:]

某人曾经曰过,除了汇编语言,其他都是语法糖……
[/Quote]
出了机械语言 其他都是语法糖
公子骏 2011-08-23
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 qq806418714 的回复:]

array_each(arrt, int, i, v,
printf("%d: %s\n", i, v);
v是个int类型的数吧,为什么用%s输出?
看到的,告诉下
[/Quote]
手误
低头思蚊香 2011-08-23
  • 打赏
  • 举报
回复
array_each(arrt, int, i, v,
printf("%d: %s\n", i, v);
v是个int类型的数吧,为什么用%s输出?
看到的,告诉下
jiangkaibo1987 2011-08-23
  • 打赏
  • 举报
回复
语法糖?
yuxi584350 2011-08-23
  • 打赏
  • 举报
回复
人气不是一般的高或
公子骏 2011-08-23
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 cfvmario 的回复:]

说实话现在需要宏的地方很少了啊……自从有了内联函数这东西
而用宏搞这事,个人觉得会降低程序可读性。。
[/Quote]
宏与内联无非是封装接口的方法,是否降低程序可读性要看怎么写。
但有些地方非用宏不可,就如本帖实现的内容,如果能用内联函数早用了。
还有很多项目要跨平台,也必须用一大堆宏来抽象底层。
公子骏 2011-08-23
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 jiandingzhe 的回复:]

糖吃太多会长虫牙的。
宏用太多会晕菜的。
[/Quote]
但你也天天在用,参考1楼所说的。
加载更多回复(30)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧