C 中变量声明优先级和错误处理的最佳实践

发布于 2024-09-05 10:25:33 字数 820 浏览 5 评论 0原文

以下两种方法中的一种是否比另一种有优势?

这里首先测试 fopen 是否成功,然后then所有变量声明都发生,以确保它们不被执行,因为它们不必

void func(void) {
    FILE *fd;

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    int a, b, c;
    float d, e, f;
    /* variable declarations */

    /* remaining code */
}

这恰恰相反。即使

void func(void) {
    FILE *fd;
    int a, b, c;
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */        
}

fopen 失败,所有变量声明都会发生,当 fopen 失败时,第二种方法是否会产生任何额外的成本? 很想听听你的想法!

is there an advantage in one of the following two approaches over the other?

here it is first tested, whether fopen succeeds at all and then all the variable declarations take place, to ensure they are not carried out, since they mustn't have had to

void func(void) {
    FILE *fd;

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    int a, b, c;
    float d, e, f;
    /* variable declarations */

    /* remaining code */
}

this is just the opposite. all variable declarations take place, even if fopen fails

void func(void) {
    FILE *fd;
    int a, b, c;
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */        
}

does the second approach produce any additional cost, when fopen fails?
would love to hear your thoughts!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

橙味迷妹 2024-09-12 10:25:34

当 fopen 失败时,应用程序将退出,因此没有人真正关心变量是否已初始化。没有任何成本,因为应用程序已经终止并且静态分配的内存已经释放。如前所述,内存甚至没有分配,但如果您将所有内存设置为默认值(例如 0),内存就会分配。即使您更改此行为,也不会产生额外成本。

另外,第二个代码可能更可取,因为它符合 C89 标准。

When fopen fails, the application exits, so nobody really cares if the variables were initialized. There is no cost, because the application has already terminated and the statically allocated memory already freed. As mentioned, the memory isn't even allocated, but it would have if you had set all of them to a default value, like 0. Even if you change this behavior, there is no additional cost.

Also, the second code is probably preferable because it is C89 compliant.

孤芳又自赏 2024-09-12 10:25:34

在这两种情况下,同一范围内函数中所有变量的堆栈变量分配可能都发生在函数的顶部,因此两种方法都可以。

Stack variable allocation for all variables in the function in the same scope likely happens at the top of your function in both cases, so either method is fine.

眼眸印温柔 2024-09-12 10:25:34

对于大多数编译器来说,示例中的变量声明不会产生额外费用。唯一可能的情况是它们具有需要任何重要代码才能生成的初始化值。

例如:

void func(const char * filename) {
    FILE *fd;
    int a, b, c;
    size_t z = strlen(filename);
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen(filename, "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */    
    /* Some code that uses z */
}

在此示例中,可能会在尝试打开文件之前调用 strlen,但从未使用过它的值。在 fopen 之后调用 strlen 可能会产生更好的代码。但这并不是最好的例子,因为编译器通常知道像 strlen 这样的几个函数是纯函数式的(没有副作用,只使用它们的参数来产生结果),并且可以将调用移动到 strlen 位于 fopen 本身下方,但您应该明白了。

The variable declarations in your example would not cost extra with most compilers. The only time they might is if they had initialization values which required any non-trivial code to produce.

For example:

void func(const char * filename) {
    FILE *fd;
    int a, b, c;
    size_t z = strlen(filename);
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen(filename, "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */    
    /* Some code that uses z */
}

In this example strlen may be called before the attempt to open the file but it's value never used. Placing the call to strlen after the fopen could result in better code. This isn't really the best example though, because compilers often know that several functions like strlen are purely functional (no side effects and only use their arguments to produce results) and could move the call to strlen below the fopen itself, but you should get the idea.

辞取 2024-09-12 10:25:34

它不应该有任何区别,但您始终可以比较两个版本的汇编输出来确定!

堆栈上的空间总是在函数入口处准备好,可能是为了为编译器/编译器编写器获得一个很好的函数,将变量名称映射到基指针+偏移量。至于初始化,它也不应该有任何区别。在将某些内容写入两个版本的变量之前,内容是未定义的。

然而,在 C++ 中,当跳过初始化时(您在示例的代码中没有这样做),您可能会遇到一些问题,但 C++ 的推理要复杂得多。

It shouldn't make any difference, but you can always compare the assembly output of the two versions to make sure!

Space on the stack is always prepared on function entry, probably in order to get a nice function mapping variable names to base pointer + offset for the compiler/compiler writer. As for initialization, it shouldn't make any difference either. The content is undefined until something is written into the variables in both versions.

In C++ however, you might get into some problems when jumping past initialization (which you aren't doing in the code in your example), but C++ is much more complicated to reason about.

箹锭⒈辈孓 2024-09-12 10:25:33

不,它没有任何成本。这两个示例很可能编译为相同的结果二进制文件。由于没有赋值的变量声明实际上在 C 中不会执行任何操作,因此它不会生成任何代码。当需要时,堆栈指针将简单地跳过可用于这些变量的空间。

No, it doesn't have any cost. Both examples most likely compile to the same resulting binary. Since variable declaration without assignment doesn't actually do anything in C, it doesn't generate any code. The space available for those variables will be simply skipped over by the stack pointer when needed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文