繁体   English   中英

在C语言中声明函数参数中的变量

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM