[英]Declaring variables in the arguments to a function in C
我有一种奇怪的愿望; 我不知道是否有任何编译器或语言扩展允许这样做。
我希望能够在函数调用中声明变量,如下所示:
int test(int *out_p) {
*out_p = 5;
return 1;
}
int main()
{
if (int ret = test(int &var)) { // int var declared inside function invocation
fprintf(stderr, "var = %d\n", var); // var in scope here
}
return 0;
}
因为然后var的范围遵循ret的范围。 再举一个例子(来自我现在正在研究的项目),我有
cmd_s = readline();
int x, y, dX, dY, symA, symB;
if (sscanf(cmd_s, "placeDomino:%d %d atX:%d y:%d dX:%d dY:%d",
&symA, &symB, &x, &y, &dX, &dY) == 6) {
do_complicated_stuff(symA, symB, x, y, dX, dY);
} else if (sscanf(cmd_s, "placeAtX:%d y:%d dX:%d dY:%d", &x, &y, &dX, &dY) == 4) {
do_stuff(x, y, dX, dY);
/* symA, symB are in scope but uninitialized :-( so I can accidentally
* use their values and the compiler will let me */
}
而我更愿意写
cmd_s = readline();
if (sscanf(cmd_s, "placeDomino:%d %d atX:%d y:%d dX:%d dY:%d",
int &symA, int &symB, int &x, int &y, int &dX, int &dY) == 6) {
do_complicated_stuff(symA, symB, x, y, dX, dY);
} else if (sscanf(cmd_s, "placeAtX:%d y:%d dX:%d dY:%d", int &x, int &y, int &dX, int &dY) == 4) {
do_stuff(x, y, dX, dY);
/* Now symA, symB are out of scope here and I can't
* accidentally use their uninitialized values */
}
我的问题是,任何编译器都支持这个吗? 如果我以正确的方式擦它,gcc是否支持它? 是否有C或C ++(草案)规范有这个?
编辑:刚才意识到在我的第一个代码示例中,我的int ret声明在C99中也没有用; 我想我被for循环宠坏了。 我也想要这个功能; 想像
while(int condition = check_condition()) {
switch(condition) {
...
}
}
或类似的东西。
除了块作用域声明之外,在C99中,基本上还有另外两种方法来声明变量,这些变量根据定义仅限于它们出现的语句:
(type name){ initializers }
并声明一个存在于当前块中的局部变量。 例如,对于函数调用,您可以使用test(&(int){ 0 })
。 for
作用域变量,只有for
语句本身的范围和依赖语句或块。 你的if
表达式与局部变量你可以做一些奇怪的事情
for (bool cntrl = true; cntrl; cntrl = false)
for (int ret = something; cntrl && test(&ret); cntrl = false) {
// use ret inside here
}
小心,这样的事情很快变得难以理解。 另一方面,优化器非常有效地减少了这些代码,并且很容易找到test
,而for
块的内部只被评估一次。
没有编译器支持这个。 我没有看到这有什么意义。
减少源代码行数并不一定会导致更高效的程序,这是一种常见的误解。 在C语言的99%的情况下,将这样的语句重写为更紧凑的语句是没有意义的。 它只会导致代码不太可读,最终你会获得完全相同的机器代码。
你应该做的是:
void some_func (void) // good example
{
... lots of code here
int ret;
int var;
ret = test(&var);
if(ret == SOMETHING)
{
fprintf(stderr, "var = %d\n", var); // var in scope here
}
}
你不应该做的是:
void some_func (void) // bad example
{
... lots of code here
{
int ret;
int var;
if((ret = test(&var))
{
fprintf(stderr, "var = %d\n", var); // var in scope here
}
}
}
好的例子和坏例子将产生完全相同的机器代码 。 这一点非常重要!
首先,坏示例中变量的范围缩小不会导致更有效的程序:编译器非常能够知道何时第一次使用变量以及何时不再使用变量。 在这两个示例中,编译器将变量ret和var存储在CPU寄存器或堆栈中。
另请注意,变量是在函数中间声明(仅限C99 / C11)还是在开头(C90或C99 / C11)声明,无论效率如何,都无关紧要。 在范围中间声明变量只是一种编程风格的特性:您正在告诉读者代码,从这一点开始,此变量开始变得重要。 与人类阅读代码相反,编译器并不关心编写声明的位置。
如果我们省略了ret并且只是检查了test()的结果,那也没有任何区别 - 函数的结果必须仍然保存在某个地方 ,或者在程序员显式声明的变量中,或者隐式地保存在临时变量中由编译器创建。 机器代码将是相同的,如果没有ret变量则更难调试。
这些例子之间的主要区别在于,坏的一个包含广泛认可的错误编程实践,例如内部条件赋值(MISRA-C:2004 13.1)和非布尔变量的零隐式测试(MISRA-C:2004 13.2) 。 添加不必要的,模糊的,额外的本地范围。
所以我的建议是学习一些汇编程序(或反汇编程序)并学习如何将C代码实际转换为机器代码。 当你知道这一点时,你不会觉得需要不假思索地混淆代码,并假设你正在改进代码。
使用空范围,如下所示:
int test(int *out_p) {
*out_p = 5;
return 1;
}
int main()
{
{
int var, ret;
if (ret = test(&var)) {
fprintf(stderr, "var = %d\n", var); // var in scope here
}
}
// var not in scope
return 0;
}
while(int condition = check_condition()) {
switch(condition) {
...
}
}
要么
if (int ret = test(int &var))
我的问题是,任何编译器都支持这个吗? 如果我以正确的方式擦它,gcc是否支持它? 是否有C或C ++(草案)规范有这个?
这不是C. if
语句或while
语句的子句必须是表达式,不能是声明。
自C99起,您的第一个子句中的for
iteration语句只能声明:
for (clause-1; expression-2; expression-3)
第1条可以是声明或表达式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.