声明vs定义局部变量

时间:2015-10-10 14:25:34

标签: c

我读到声明和定义全局变量之间存在差异。我的理解是,在下面的代码中," a"在main之外声明(刚刚声明时没有分配内存),并且只有在真正赋值给它时才定义。但是在变量C的情况下,没有分配内存,因为没有使用它。在变量d的情况下,它是声明和初始化。 或者声明是否意味着使用extern关键字声明变量?

在变量d的情况下会发生什么?假设它没有在任何地方使用,编译器会删除它吗?

int a;    // declaration
int c;    // declaration
int d=10;
int main (void)
{
    a=50;  // a is now allocated memory
    printf"%d",a);
}

但是当谈到局部变量时,我们是否只声明了概念,但是没有分配内存?我读到的地方只是说int b;将在堆栈中分配内存。如果没有使用,在下面的情况下是否将任何内存分配给变量b?我的理解是"否"因为我们并没有真正使用该变量,编译器会进行优化并在这种情况下删除b。

void func1(void)
{
int b;
printf("Hello");
}

我想知道使用和不使用extern声明的确切区别,定义全局范围和本地范围。

更新 澄清不是重复问题:我问的确切问题是关于局部变量声明,初始化(内存分配)以及与全局变量初始化/声明的比较。在全局变量中,我们使用"暂定"暂时宣布但不分配记忆。为什么在当地人看不到同样的概念是我的困惑。如果声明并且未使用局部变量会发生什么。是否在堆栈中分配内存。

2 个答案:

答案 0 :(得分:2)

在设置变量值时,内存不是分配,内存由链接器和加载器提交给每个已定义的全局变量。

未初始化的全局变量在程序开始时设置为00.0或空指针,具体取决于其类型。

未初始化的局部变量在设置之前具有不确定的值。在设置它们之前取消引用它们会调用未定义的行为。

在您的示例中,ab在调用0时具有值mainb不应在函数func1中进行评估在设置之前。

在Ansi C之前,可以在多个源文件中定义相同的全局变量,只要所有定义都相同且没有初始化程序。此编码样式已弃用,但出于兼容性原因仍受支持。现代连接器会抱怨这种情况。

感谢Olaf的额外精确度:int a;确实是暂定定义。允许在提供初始化器的同一翻译单元中进一步定义另一个定义。这样做的基本原理是允许初始化器交叉引用其他变量,例如在这个例子中:

void *p1;   // tentative definition
void *p2 = &p1;   // regular definition
void *p1 = &p2;  // actual definition with an initializer

static void *p3;   // tentative definition
static void *p4 = &p3;   // regular definition
static void *p3 = &p4;  // actual definition with an initializer

在同一翻译单元中缺少其他定义的情况下,暂定定义成为实际定义。

在上面的示例中,使用extern关键字更具可读性,并使p1的暂定定义只是一个声明,但static变量{没有其他选择{ {1}}。

更新:无论是否使用初始值,都无法声明局部变量,仅定义局部变量。本地范围的p3声明一个带有extern链接的全局变量,其名称a仅在声明范围内已知。它本身并不是一个局部变量,而且非常不鼓励这种冒险和混乱的风格。

答案 1 :(得分:0)

编译时

router.get('/:someParameter', function(req, res, next) {
    var query = {}; // your query
    User.findOne(query, function(err, user) {
        if (err) return next(err); // handle error case
        res.json(user);
    });
});

int int a; // declaration int c; // declaration int d=10; int main (void) { a=50; // a is now allocated memory printf"%d",a); } 并使用main.o分析生成的符号,您将获得:

nm main.o

来自0000000000000004 C a 0000000000000004 C c 0000000000000000 D d 0000000000000000 T main U printf

  

“C”符号很常见。常用符号是未初始化的数据。   链接时,多个常用符号可能会出现相同的名称。   如果符号在任何地方定义,则将公共符号视为                      未定义的参考文献。

     

“d”
  符号位于初始化数据部分。

换句话说,man nm表示暂时为int a;分配单位化内存,并使用a符号标记该内存。在链接时,如果所有翻译单元都具有此类型的a符号,则它将变成一个共享的明确(“B”)单元化存储器分配(技术上不是未初始化的,因为“单元化”静态数据总是归零)。如果一个翻译单元执行a,它将变为一个初始化为42的共享确定内存分配。如果多个翻译单元尝试在全局范围内将值设置为int a=42,您将获得链接器错误。

如果您a并且在代码中至少使用了一次符号extern int e;,那么e符号的类型将为e,就像{{ {1}},但如果没有链接的翻译单元提供它,则会出错。如果您U并且不使用它,则不会为其生成符号。

简而言之,非完整的全局声明会保留内存并且无法进行优化(除非在链接阶段)。 可以优化堆栈中未使用的东西。