c99转到过去的初始化

R S*_*hko 22 c gcc goto c99

在调试崩溃时,我在一些代码中遇到了这个问题:

int func()
{
    char *p1 = malloc(...);
    if (p1 == NULL)
        goto err_exit;

    char *p2 = malloc(...);
    if (p2 == NULL)
        goto err_exit;

    ...

err_exit:
    free(p2);
    free(p1);

    return -1;
}
Run Code Online (Sandbox Code Playgroud)

第一个malloc失败时会出现问题.因为我们跳过初始化p2,它包含随机数据和调用可能free(p2)会崩溃.

我希望/希望这将与C++中的方式相同,其中编译器不允许goto跳过初始化.

我的问题:是跳过标准允许的初始化还是这是gcc实现c99的错误?

flo*_*rin 17

当你通过使用跳过变量定义时,你可以要求gcc警告你-Wjump-misses-init,然后你可以使用-Werror(或更确切地说-Werror=jump-misses-init)强制用户处理它.此警告包含在内,-Wc++-compat因此gcc开发人员知道代码在C与C++中的行为不同.

您也可以稍微更改代码:

int func()
{
    char *p1 = malloc(...);
    if (p1 == NULL)
        goto err_exit_1;

    char *p2 = malloc(...);
    if (p2 == NULL)
        goto err_exit_2;

    ...

err_exit_2:
    free(p2);
err_exit_1:
    free(p1);

    return -1;
}
Run Code Online (Sandbox Code Playgroud)

...并且只保持标签与初始化变量的配对.使用单元化变量调用许多其他函数时会遇到同样的问题,free恰好是一个更明显的函数.

  • 你实际上可以做得更好 - `-Werror = jump-missses-init`只会将那个警告变成一个错误(我认为这可以从gcc 4.3开始提供). (12认同)
  • @nategoose - `free(NULL)`是合法的,被定义为无操作. (4认同)
  • 有点偏离主题,但是当我在它的时候,gcc也理解`-Wno-error = ...`,这样你就可以将所有警告转为错误,然后排除某些错误,如果你愿意的话. (3认同)
  • @nategoose:On可以称之为"低效率",但这不是错误.`free(NULL)`是完全合法的事情. (3认同)

AnT*_*AnT 9

这样的跳跃确实是标准允许的,所以这不是GCC中的错误.该标准将此情况列为附件I中的建议警告.

在范围方面对C99跳转的唯一限制是跳入变量修改类型变量的范围是非法的,如VLA

int main() {
  int n = 5;
  goto label; // <- ERROR: illegal jump
  int a[n];
label:;
}
Run Code Online (Sandbox Code Playgroud)

换句话说,说"跳跃只是C中的跳跃"是不正确的.在进入变量范围时,跳转受到一些限制,尽管不像C++那样严格.您描述的情况不是受限制的情况之一.


Pat*_*ter 6

嗯,并不是因为新标准允许在任何地方声明变量,所以使用它总是一个好主意。对于你的情况,我会像我们在经典 C 中所做的那样。

int func()
{
char *p1 = NULL;    /* So we have a defined value */
char *p2 = NULL;

  p1 = malloc(...);
  if(!p1)
    goto err_exit;

  p2 = malloc(...);
  if(!p2)
    goto err_exit;

  ...

  err_exit:
    free(p2);
    free(p1);

  return -1;
}
Run Code Online (Sandbox Code Playgroud)