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

在C中函数的参数中声明变量,c,function,variables,declaration,invocation,C,Function,Variables,Declaration,Invocation,我有一种奇怪的愿望;我不知道是否有任何编译器或语言扩展允许这样做 我希望能够在函数调用中声明变量,如下所示: 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", v

我有一种奇怪的愿望;我不知道是否有任何编译器或语言扩展允许这样做

我希望能够在函数调用中声明变量,如下所示:

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;
}
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;
}
因为var的范围遵循ret的范围

我更喜欢写作

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中也不好;我想我已经被这个循环宠坏了。我也想要这个功能;想象

while(int condition = check_condition()) {
    switch(condition) {
        ...
    }
}

或者类似的

使用空范围,如下所示:

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;
}
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;
}

我的问题是,有没有编译器支持这一点?如果我使用正确的方法,gcc是否支持它?是否有C或C++(草案)规格有这个? 这不是C。if语句或while语句的
子句必须是表达式,不能是声明

对于
for
iteration语句,在其第一个子句中只能有一个自C99以来的声明:

for (clause-1; expression-2; expression-3)

子句-1可以是一个声明或表达式。

除了块范围声明之外,在C99中,基本上还有两种声明变量的方法,根据定义,这些变量仅限于它们出现的语句:

  • 复合文字的形式为
    (类型名称){initializers}
    ,并声明存在于当前块中的局部变量。例如,对于函数调用,您可以使用
    test(&(int){0})
  • for
    范围变量仅具有
    for
    语句本身和依赖语句或块的范围
如果你的
表达式带有局部变量,你可以做一些奇怪的事情,比如

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
    }
  }
}
您不应该做的是:

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代码实际上是如何翻译成机器代码的。当您知道这一点时,您就不会觉得有必要用错误的假设来混淆代码,以为您正在改进它。

是的,这确实有效;但它缺乏简洁性。我想我的建议不是那么简洁,但我希望至少有一点语法上的甜点。这不是C,如果
子句必须是一个表达式,不能是来自OP:-)的声明复制粘贴,我将声明移动到与var相同的级别。你会为了简洁而牺牲清晰度吗?我确实说过“奇怪的愿望”:-p我通常认为简洁可以提高清晰度;这就是为什么我更喜欢在我能找到它们的地方使用让我简洁的习语。“不过,我在这个成语上可能运气不好。”瓦卡尼诺说。你知道现在键盘要多少钱吗?我们所说的键盘成本每十年至少10美元!显然,键盘的磨损应该是任何成功程序员最关心的问题。@zmccord您可能应该澄清您的兴趣是在生产代码中使用它,还是只是对C语言的内部工作方式感到好奇。如果是后者,请在帖子中添加“语言律师”标签,以防止其获得接近票数的选票;我也知道,尽管我在最初的帖子中没有充分阐明这一点,但这在C99中并不是标准的,我更多地是在寻找具有这一特征的扩展方言。我正在做的项目中的例子是认真的;我希望此功能可以简化我的代码,并帮助compi