什么情况下可以在定义中使用extern变量?

发布于 2024-12-14 13:01:24 字数 1190 浏览 3 评论 0原文

我非常非常抱歉。我不知道我不完整的代码附件会造成如此混乱。很高兴看到这么多真诚的帮助。

此代码将编译:

int myadd(int, int);
static int main_stat = 5;

int main()
{
    int i, j;
    main_stat = 13;
    j = myadd(-1,7);
    i = main_stat;

    cout << j << i;     //  3  and 13
    return 0;

}

myadd.cpp

extern int main_stat = -3;
int myadd(int x,int y)
{
    int t = main_stat;
    t = x + y;
    y = t +main_stat;
    return y;    // will return 3
}

请参阅我定义的外部链接 main_stat。为什么这是合法的?我以为你只能链接而不能定义。

myadd 函数调用的堆栈帧中是否分配了存储空间?全局静态分配在堆上,我相信,对吧?


编辑

我很抱歉,但我想这次我会缩小我的问题范围:

来自 C++ Primer 4ed

extern 声明可以包含初始化程序(当组合时 仅当它出现在函数外部时才成为定义。

我很清楚单一定义规则。

Q1. myadd(int,int) 被调用时使用 main_stat 的哪个副本?与主副本相同,但具有不同的值(我可以测试)?或者每个函数都有自己的静态全局副本?

Q2。堆上是否为这些全局静态变量分配了内存?我知道很多事情都需要实现,但是堆不是用于静态变量吗?

Q3。我知道以下两个是有效的,

extern int x;    // means int x is defined elsewhere
extern int x = 3;  // declared and defined 

如果我们可以在 myadd 的命名空间中声明一个静态全局变量,为什么我们需要第二个?它如何像 aschepler 所说的那样让事情变得清晰

I am very very sorry. I didn't know my incomplete code attachment would create such a mess. I am very glad to see so many sincere helps.

This code will compile:

int myadd(int, int);
static int main_stat = 5;

int main()
{
    int i, j;
    main_stat = 13;
    j = myadd(-1,7);
    i = main_stat;

    cout << j << i;     //  3  and 13
    return 0;

}

myadd.cpp

extern int main_stat = -3;
int myadd(int x,int y)
{
    int t = main_stat;
    t = x + y;
    y = t +main_stat;
    return y;    // will return 3
}

See I defined and extern linking main_stat. Why is that legal? I thought you could only link and not define.

Is storage allocated in the stack frame of myadd function call? Global static are allocated on heap, I believe, right?


EDIT

I am sorry, but I think this time I will narrow down my questions:

From C++ Primer 4ed

An extern declaration may include an initializer (when combined
becomes definition) only if it appears outside a function.

I am clear about one-definition rule.

Q1. Which copy of main_stat does myadd(int,int) uses when it is called? The same copy as the main has, but with a different value (which I can test) ? Or does each function has its own static global copy?

Q2. Is memory allocated on the heap for these global static variables? I know many things are up to implementation, but isn't heap used for static variables?

Q3. I know the followings two are valid

extern int x;    // means int x is defined elsewhere
extern int x = 3;  // declared and defined 

Why do we want the second one if we can just declare a static global variable within the namespace of myadd ? How does it make things clear like aschepler said?

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

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

发布评论

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

评论(6

爱她像谁 2024-12-21 13:01:24

所有带有初始值设定项的变量声明也是定义;
这是一条压倒一切的规则。无论extern如何。甚至还有
在定义上需要 extern 的情况:您只能
使用具有外部链接的变量实例化模板。和
const 变量默认具有内部链接,因此您需要
例如:

extern int const i = 42;

如果您想使用它来实例化 template

All variable declarations with an initializer are also definitions;
that's an overriding rule. Regardless of extern. There are even
cases where you need an extern on a definition: you can only
instantiate a template using a variable which has external linkage. And
const variables have internal linkage by default, so you need
something like:

extern int const i = 42;

if you want to use it to instantiate a template<int const*>.

被翻牌 2024-12-21 13:01:24

以下是声明和定义:

int x;

添加 extern 表示“请仅将其设为声明”。

但是当您提供一个值时,该行必须是一个定义,因此该变量获得extern存储类,并且您恰好在适当的位置定义了它:

extern int x = 3;

链接语义与 extern 的通常情况相同,存储位置与正常定义 int x = 3 一样 — 即在命名空间的 TU 中范围。 myadd 根本不相关。


这是一个很难“证明”的问题,因为这是一个“没有规则反对它”的案例。

这是最好的引用:

[n3290: 3.1/2]: 声明就是定义,除非它声明
一个没有指定函数体的函数(8.4),它
包含extern说明符(7.1.1)或链接规范25(7.5)既不是初始化程序也不是
函数体
,[..]

以及其他一些相关信息:

[n3290: 3.5/2]: 当名称可能表示相同的对象、引用、函数、类型、模板、命名空间或值作为另一个范围中的声明引入的名称:

  • 当名称具有外部链接时,它所表示的实体可以通过其他翻译单元范围或同一翻译单元的其他范围的名称来引用。
  • 当名称具有内部链接时,它所表示的实体可以被同一翻译单元中其他范围的名称引用。
  • 当名称没有链接时,它所表示的实体不能被其他范围的名称引用。

[n3290: 3.5/12]:块作用域中声明的函数名称和块作用域 extern 声明声明的变量名称
有联动。如果实体有一个可见的声明
具有相同名称和类型的链接,忽略声明的实体
在最里面的封闭命名空间范围之外,即块范围
声明声明同一实体并接收该实体的链接
先前的声明。如果有多个这样的匹配实体,
该程序格式不正确。否则,如果没有找到匹配的实体,
块作用域实体接收外部链接。 [..]

The following is a declaration and definition:

int x;

Adding extern says "make it a declaration only, please".

But when you are providing a value, the line has to be a definition, so the variable gets extern storage class and you just happen to be defining it right in place anyway:

extern int x = 3;

The linkage semantics are as they usually are for extern, and the storage location is just as it would be for a normal definition int x = 3 — i.e. in that TU at namespace scope. myadd is not relevant at all.


It's a hard one to "prove", because it's a case of "there's no rule against it".

Here's the best quote:

[n3290: 3.1/2]: A declaration is a definition unless it declares
a function without specifying the function’s body (8.4), it
contains the extern specifier (7.1.1) or a linkage-specification25 (7.5) and neither an initializer nor a
function-body
, [..]

And some other pertinent information:

[n3290: 3.5/2]: A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope:

  • When a name has external linkage, the entity it denotes can be referred to by names from scopes of other translation units or from other scopes of the same translation unit.
  • When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in the same translation unit.
  • When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.

[n3290: 3.5/12]:The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration
have linkage. If there is a visible declaration of an entity with
linkage having the same name and type, ignoring entities declared
outside the innermost enclosing namespace scope, the block scope
declaration declares that same entity and receives the linkage of the
previous declaration. If there is more than one such matching entity,
the program is ill-formed. Otherwise, if no matching entity is found,
the block scope entity receives external linkage. [..]

伊面 2024-12-21 13:01:24
extern int main_stat=-3;  

声明并定义main_stat,While:

extern int main_stat;      

仅声明变量main_stat

您可以拥有任意数量的声明,但只能拥有一个定义。

关键字extern表示外部链接。如果没有它,main_stat 将是静态的并具有内部链接,并且您不能使用另一个翻译单元的 main_stat

存储空间是否在 myadd 的堆栈帧中分配?

不,绝对不在 add 的堆栈框架上。
内存分配的位置是实现定义的,但您可以保证该对象在整个程序持续时间内都处于活动状态。

extern int main_stat=-3;  

declares and defines main_stat, While:

extern int main_stat;      

just declares the variable main_stat.

You can have as many declarations as you want but you can have only one Definition.

The keyword extern, indicates External Linkage. Without it main_stat would be static and have Internal linkage and you cannot not use main_stat from another translation unit.

Is storage allocated in the stack frame of myadd ?

No definitely not on the stackframe of add.
Where the memory is allocated is implementation defined but you have the assurance that the object will be alive throughout the duration of the program.

讽刺将军 2024-12-21 13:01:24

这个问题显然源于一些误解。

有些人认为 extern 关键字总是将定义变成非定义声明。这根本不是真的。

关键字extern 只是给出声明的实体外部链接。它可以应用于声明。它可以应用于定义(请记住,定义也是声明)。

因此,说无法定义 extern 实体是绝对不正确的。一个可以。这完全没有问题。

造成混乱的原因通常是,当您将 extern 应用于类似定义时,

int x; // no initializer

该定义突然变成了非定义声明。这是事实,但这只不过是必须记住的 extern 关键字的一次性怪癖。如果您采用类似的定义

int x = 42;

,那么对其应用 extern 关键字仍会将其保留为定义,即在这种情况下没有怪癖。

The question apparently stems from some misconception.

Some people believe that extern keyword always turns a definition into a non-defining declaration. This is simply not true.

The keyword extern simply gives the declared entity external linkage. It can be applied to declarations. It can be applied to definitions (and remember that definitions are declarations as well).

So, saying that one can't define an extern entity is absolutely incorrect. One can. There's no problem with that at all.

The confusion is usually caused by the fact that when you apply extern to a definition like

int x; // no initializer

that definition suddenly turns into a non-defining declaration. This is true, but this is is no more than a one-off quirk of extern keyword that has to be remembered. If you take a definition like

int x = 42;

then applying the extern keyword to it will still preserve it as a definition, i.e. no quirks in this case.

自我难过 2024-12-21 13:01:24

首先,根据您的评论,包含 main 函数的文件具有定义 static int main_stat = 10;。您应该知道,这与您在包含 myadd 的文件中定义的变量不同,因为作为静态变量,其范围仅限于该文件。事实上,由于具有相同名称的静态变量,main 无法访问您在此文件中定义的变量。

但这并不意味着这两个变量都是在堆栈上创建的。两者都是单独的全局变量,只是包含 main 的文件中的变量 main_stat (我简称该文件为 main 文件,这个 myadd 文件)是在任何其他文件中不可用,而您在此处定义的变量 main_stat 可以从包含声明 extern main_stat; 的任何文件访问(注意:没有初始化程序!)。但是,主文件不能包含此声明,因为它会与同名的静态变量冲突。

请注意,给出初始值设定项会使变量声明成为定义,也就是说,它与省略 extern 相同(但请注意,如果将变量声明为常量,则不能省略 extern,因为常量默认为静态)。唯一不是定义的全局 extern 声明是那些带有 extern,但不带有初始化器的声明。

First, according to your comment, the file containing the main function has the definition static int main_stat = 10;. You should be aware that this is not the same variable as you defined in the file containing myadd because as static variable its scope is restricted to that file. Indeed, thanks to that static variable with the same name, main is not able to access the variable you defined in this file.

But that doesn't mean that either variable was created on the stack. Both are separate global variables, it's just that the variable main_stat in the file containing main (I'll call that file main file for short, and this one myadd file) is not available in any other file, while the variable main_stat you defined here can be accessed from any file which contains the declaration extern main_stat; (note: without initializer!). The main file cannot contain this declaration, however, because it would conflict with the static variable of the same name.

Note that giving an initializer makes your declaration of the variable a definition, that is, it's the same as if you had omitted the extern (note however that if a variable is declared constant, the extern may not be omitted because constants are by default static). The only global extern declarations which are not also definitions are those with extern, but without initializer.

叫嚣ゝ 2024-12-21 13:01:24

其他人都很好地介绍了这一点,但只是为了在一个地方显示变体:

int x;                    // #1

是声明和定义。 x 的初始值为零。

int x = 3;                // #2

是一个声明和定义。

const int cx;             // #3

在 C++ 中是非法的。

const int cx = 3;         // #4

是一个声明和定义,但是如果这是翻译单元中的第一个声明,则 cx 具有内部链接。

extern int x;             // #5

是一个声明,但不是一个定义。程序中的其他地方必须有 x 的定义。

extern int x = 3;         // #6

是一个声明和一个定义。 extern 是不必要的,但它使事情变得清晰。

extern const int cx;      // #7

是一个声明,但不是一个定义。程序中的其他地方必须有 cx 的定义。

extern const int cx = 3;  // #8

是一个声明和一个定义。除非已经看到上面的先前声明,否则需要 extern

Everyone else has covered this pretty well, but just to show the variants in one place:

int x;                    // #1

is a declaration and definition. The initial value of x is zero.

int x = 3;                // #2

is a declaration and definition.

const int cx;             // #3

is illegal in C++.

const int cx = 3;         // #4

is a declaration and definition, but cx has internal linkage if this is its first declaration in the translation unit.

extern int x;             // #5

is a declaration but NOT a definition. There must be a definition of x somewhere else in the program.

extern int x = 3;         // #6

is a declaration and a definition. The extern is unnecessary, but makes things clear.

extern const int cx;      // #7

is a declaration but NOT a definition. There must be a definition of cx somewhere else in the program.

extern const int cx = 3;  // #8

is a declaration and a definition. The extern is needed unless the previous declaration above was already seen.

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