我读到声明和定义全局变量之间存在差异。我的理解是,在下面的代码中," 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声明的确切区别,定义全局范围和本地范围。
更新 澄清不是重复问题:我问的确切问题是关于局部变量声明,初始化(内存分配)以及与全局变量初始化/声明的比较。在全局变量中,我们使用"暂定"暂时宣布但不分配记忆。为什么在当地人看不到同样的概念是我的困惑。如果声明并且未使用局部变量会发生什么。是否在堆栈中分配内存。
答案 0 :(得分:2)
在设置变量值时,内存不是分配,内存由链接器和加载器提交给每个已定义的全局变量。
未初始化的全局变量在程序开始时设置为0
,0.0
或空指针,具体取决于其类型。
未初始化的局部变量在设置之前具有不确定的值。在设置它们之前取消引用它们会调用未定义的行为。
在您的示例中,a
和b
在调用0
时具有值main
,b
不应在函数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
并且不使用它,则不会为其生成符号。
简而言之,非完整的全局声明会保留内存并且无法进行优化(除非在链接阶段)。 可以优化堆栈中未使用的东西。