代码之家  ›  专栏  ›  技术社区  ›  mcjabberz

C语言中的变量声明放置

  •  111
  • mcjabberz  · 技术社区  · 16 年前

    以下代码使用成功编译 gcc -std=c89 gcc -ansi

    #include <stdio.h>
    int main() {
        int i;
        for (i = 0; i < 10; i++) {
            char c = (i % 95) + 32;
            printf("%i: %c\n", i, c);
            char *s;
            s = "some string";
            puts(s);
        }
        return 0;
    }
    

    这些声明不应该吗 c s

    7 回复  |  直到 9 年前
        1
  •  162
  •   MarcH rhardih    5 年前

    它编译成功,因为GCC允许声明 s 作为GNU扩展,即使它不是C89或ANSI标准的一部分。如果你想严格遵守这些标准,你必须通过考试 -pedantic 旗帜

    声明 c 一开始 { }

        2
  •  78
  •   Nayuki James111    9 年前

    范围块 .

    那么,你的 char c 声明是有效的,因为它位于for循环作用域块的顶部。但是, char *s

        3
  •  43
  •   afk    5 年前

    在块顶部对变量声明进行分组可能是一个遗留问题,这可能是由于旧的原始C编译器的限制。所有现代语言都建议,有时甚至强制在最晚的点声明局部变量:它们的第一次初始化点。因为这样可以避免错误使用随机值的风险。分离声明和初始化还可以防止在可能的情况下使用“const”(或“final”)。

    • C++引用的设计甚至不允许这种块的分组。
    • 对象 然后你免费支付一个额外的构造器的费用。如果no-arg构造函数不存在,那么您甚至不允许将两者分开!

    如果您担心找不到声明局部变量的位置,那么这意味着您有一个更大的问题:封闭块太长,应该拆分。

    https://wiki.sei.cmu.edu/confluence/display/c/DCL19-C.+Minimize+the+scope+of+variables+and+functions

        4
  •  22
  •   Adam Liss    16 年前

    从可维护性(而不是语法)的角度来看,至少有三种思路:

    1. 在函数的开头声明所有变量,这样它们就在一个地方,您就可以一眼看到完整的列表。

    2. 声明所有变量,使其尽可能靠近第一次使用它们的位置,这样您就知道了 为什么? 每个都是需要的。

    3. 在最里面的作用域块的开头声明所有变量,这样它们将尽快超出作用域,并允许编译器优化内存,并告诉您是否意外地在不希望的地方使用它们。

    我通常更喜欢第一个选项,因为我发现其他选项经常迫使我搜索声明的代码。预先定义所有变量还可以更容易地从调试器初始化和监视它们。

    有时我会在一个较小的作用域块中声明变量,但这只是出于一个很好的理由,我很少有这样的理由。一个例子可能是在 fork() ,以声明子进程只需要的变量。对我来说,这个视觉指示器是一个有用的提醒他们的目的。

        5
  •  7
  •   Gaidheal    13 年前

    C89要求在每个范围内的任何其他语句之前声明变量,随后的标准允许更接近使用的声明(这可以更直观、更高效),尤其是在“for”循环中同时声明和初始化循环控制变量。

        6
  •  0
  •   Philippe Carphin    6 年前

    如前所述,关于这一点有两个学派。

    2) 声明最接近首次使用,并且在尽可能小的范围内。

    我的答案是两者都做!让我解释一下:

    因此,我在顶级创伤后应激障碍(PTSD)中制定了宣言,并尝试虔诚地执行选项2)。

    我回到选项一是因为一件事:短函数。如果你的函数足够短,那么你将有很少的局部变量,因为函数很短,如果你把它们放在函数的顶部,它们仍然会接近第一次使用。

    此外,当您希望在顶部声明,但尚未进行初始化所需的一些计算时,“declare and set to NULL”的反模式也得到了解决,因为您需要初始化的内容可能会作为参数接收。

    但是,如果您正在处理一个长函数,那么请将最接近于第一次使用的东西放在首位,因为这样会更容易提取方法。

    我的食谱是这个。对于所有局部变量,获取该变量并将其声明移到底部,编译,然后将声明移到编译错误之前。这是第一次使用。对所有局部变量执行此操作。

    int foo = 0;
    <code that uses foo>
    
    int bar = 1;
    <code that uses bar>
    
    <code that uses foo>
    

    {
        int foo = 0;
        <code that uses foo>
    }
    
    int bar = 1;
    <code that uses bar>
    
    >>> First compilation error here
    <code that uses foo>
    

    这不会编译,因为还有一些代码使用foo。我们可以注意到,编译器能够遍历使用bar的代码,因为它不使用foo。在这一点上,有两种选择。机械的方法是向下移动“}”直到编译,另一种方法是检查代码并确定顺序是否可以更改为:

    {
        int foo = 0;
        <code that uses foo>
    }
    
    <code that uses foo>
    
    int bar = 1;
    <code that uses bar>
    

    需要注意的另一件事是,是否需要在使用foo的代码块之间保留foo的值,或者两者都是不同的foo。例如

    int i;
    
    for(i = 0; i < 8; ++i){
        ...
    }
    
    <some stuff>
    
    for(i = 3; i < 32; ++i){
        ...
    }
    

    这些情况需要的不仅仅是我的程序。开发人员必须分析代码以确定要做什么。

    完成这一机械部分后,分析数据的位置就变得更容易了。如果在一个大范围块中使用了一个变量,那么分析这种情况,看看您是否只是将同一个变量用于两个不同的事情(比如一个“i”用于两个for循环)。如果使用是不相关的,则为每个不相关的使用创建新变量。

        7
  •  -1
  •   junwanghe    12 年前

    我将引用gcc 4.7.0版手册中的一些陈述,以获得清晰的解释。

    我认为您问题的关键是,为什么即使使用了“-std=C89”选项,gcc也不符合C89。我不知道gcc的版本,但我认为不会有太大的区别。gcc的开发人员告诉我们“-std=c89”选项只意味着与c89冲突的扩展被关闭。因此,它与一些在C89中没有意义的扩展无关。不限制变量声明位置的扩展属于与C89不矛盾的扩展。

    老实说,每个人一看到选项“-std=C89”,就会认为它应该完全符合C89。但事实并非如此。 至于一开始就声明所有变量的问题是好是坏只是习惯问题。

        8
  •  -1
  •   Dang_Ho    5 年前

    您应该在函数的顶部或“局部”声明所有变量。答案是:

    视情况而定 在您使用的系统类型上:

    它确实允许您使用动态内存(例如:calloc、malloc、new…)。假设你在一个非常大的项目中工作,有1000名工程师。如果他们分配了新的动态内存,却忘记删除它(当它不再使用时),该怎么办?如果嵌入式系统长时间运行,将导致堆栈溢出和软件损坏。不容易确保质量(最好的方法是禁止动态内存)。

    如果一架飞机在30天内运行并且没有关闭,如果软件损坏(当飞机仍在空中时),会发生什么情况?

    2/其他系统,如web、PC(内存空间大):

    您应该声明变量“local”以使用优化内存。如果这些系统运行了很长时间,并且发生堆栈溢出(因为有人忘记删除动态内存)。只需做一件简单的事情来重置电脑:P它对生活没有影响