c - 如何在 C 中实现 Go 的 defer() 以便允许声明变量?
问题描述
解决方案
正如我在评论中所说,我的建议是首先避免使用这样的东西。无论您的视频说了什么或暗示了什么,现代 C 程序员的普遍观点是应该尽量减少宏的使用。类变量宏通常应该表示与上下文无关的常量值,类函数宏通常更好地实现为实际函数。这并不是说必须避免所有宏的使用,但是大多数现代 C 专业人士在复杂宏上看起来很糟糕,而且您defer()
的复杂性足以满足要求。
此外,尝试将其他语言的风格和习语导入 C 对您自己没有任何好处。每种语言的常用习语之所以成立,是因为它们适用于该语言,而不是通常因为它们具有内在的内在价值。我建议你学习 C 和 C 程序员使用的习语,而不是如何编写看起来像 Go 的 C 代码。
话虽如此,让我们考虑一下您的defer()
宏。你写,
然而问题是不能通过代码来启动声明新变量的代码段
,但实际上限制比这更强。因为宏start
在逗号表达式 ( start,0
) 中使用参数,所以它本身必须是表达式。不允许任何形式的声明或完整陈述。for
这仅与出现在语句控制块的第一个子句中的表达式间接相关。(这同样适用于end
论点。)
还可能需要注意的是,如果关联语句的执行通过通过or语句end
从块分支出来或通过执行不返回的函数(例如or )终止,则宏扩展为无法评估表达式的代码可能也很重要。此外,与 Go 不同的是,表达式是在提供的语句之后完整计算的——之前没有对它的任何部分进行计算,这可能会让 Go 程序员感到惊讶。这些也是下面介绍的选项的特征。return
goto
exit()
longjmp()
defer
end
如果您只想将start
andend
作为宏参数传递,并且您希望允许声明出现在 中start
,那么您可以这样做:
// Option 1
#define defer(start,end) start; for( \
int macro_var_line(done) = 0; \
!done; \
(macro_var_line(done) += 1), (end))
这从宏的替换文本start
中的for
语句移到可能出现任意 C 代码的位置。但是请注意,任何变量声明都将被限定在最里面的包含块中。
如果您想限制声明的范围,那么还有这个替代方案和变体,我发现它比原来的更直接:
// Option 2
#define defer(start, end, body) { start; body end; }
你会像这样使用它:
defer(FILE *f = fopen("log.txt","a+"), fclose(f), // argument list continues ...
fprintf(f,"Some message, f=%p",f);
);
这有点适合您的特定示例,因为它假设主体是作为零个或多个完整语句的序列(可以包括块、流控制语句等)给出的。如您所见,它还要求将主体作为宏参数传递,而不是出现在宏调用之后,但我认为这是一个优势,因为它有助于识别延迟代码的启动点。
推荐阅读
- sql - 根据另一个表上的数据分离一个表上的数据
- javascript - 带有回调参数的测试方法
- android - ClassNotFoundException DynamiteModuleInitializer Android
- javascript - 了解代码片段中的条件运算符和条件赋值
- c# - asp.net mvc 5中的下拉列表不同
- php - while循环只输出一行
- c - 如果文件不退出,则在 C 中创建和写入
- java - 带有 WildFly 的 JavaEE:未找到剩余资源 - 为什么?
- matlab - 从混合单元格/字符串转换/创建矩阵的有效方法
- java - RxJava2 组合多个 observable 使它们返回单个结果