【问题标题】:A global variable in C++ can be called?可以调用C++中的全局变量吗?
【发布时间】:2014-03-14 03:54:55
【问题描述】:

所以我翻阅了几本旧的 C++ 测试书籍,发现其中一个问题的解决方案非常酷!我以前从未见过这种“语法”,想问是否有人知道它实际上是如何工作的,以及为什么它没有被广泛教授!


问题: 将输出交给以下代码 ->

int g =10; //TAKE NOTE OF THIS VARIABLE

void func(int &x, int y){
    x = x-y;
    y = x*10;
    cout << x << ',' << y << "\n";
}

void main(int argc, char** argv){
    int g = 7;    //Another NOTE
    func(::g,g); // <----- "::g" is different from "g"
    cout << g << ',' << ::g << "\n";

    func(g,::g);
    cout << g << ',' << ::g << "\n";
}

输出:

3,30

7,3

4,30

4,3


我的问题是“::(variable)”语法是如何工作的?它获取存储在主外部的变量,但是该内存存储在哪里(堆栈/堆)?我们可以通过指针改变那个“全局”变量的值吗?

我认为这可能允许一些非常酷的实现,并希望与像我一样不知道这一点的人分享这些知识:)

【问题讨论】:

  • 全局变量不受欢迎,因为您无法为它们建立不变量(每个人都可以访问它们),并且您需要唯一的名称。 :: 称为作用域解析运算符,它通常用于访问命名空间(如全局命名空间)。
  • 这就像在std 命名空间中使用std::cout 访问cout

标签: c++ variables syntax global


【解决方案1】:

我的问题是“::(variable)”语法是如何工作的?

::范围解析 运算符。前面有一个类或命名空间的名称,这意味着它后面的名称在该类或命名空间内。与这里一样,它之前没有任何内容,这意味着它之后的名称在全局命名空间中作用域;也就是说,它是在任何类、函数或命名空间之外声明的。

通常,您可以通过名称引用全局变量,而不需要::。这里需要它,因为全局被同名的局部变量隐藏。这是避免使用全局变量的原因之一:如果添加隐藏代码的声明,代码的含义可能会发生变化。

内存存储在哪里(堆栈/堆)?

它在静态存储中,既不在堆栈上,也不在堆上。存储在程序开始时分配,一直持续到结束。

如果变量的类型很复杂,它可能要等到程序启动一段时间后才会被初始化;当您的代码在初始化之前使用它时,您可能会遇到一些晦涩难懂的错误。这是避免使用全局变量的另一个原因。

我们可以通过指针改变那个“全局”变量的值吗?

是的。您的示例做到了这一点,尽管使用的是引用而不是指针。它也可以直接更改,例如::g = 42;,任何时候都可以使用任何代码,因此很难推断包含它们的程序的状态。这是避免使用全局变量的另一个原因。

我认为这可能允许一些非常酷的实现

由于我在这里和其他地方提到的原因,全局变量几乎总是比它们的价值更麻烦。如果我是你,我会避开他们。

【讨论】:

  • 非常喜欢!我似乎错误地使用了命名空间 std,我发现这显然不是正确的规范!这现在更有意义了:)
  • @Scarecrow:namespace std 是标准库所在的位置,以使其与您在全局命名空间或您自己的命名空间中声明的任何内容分开。你不应该自己在里面声明任何东西。
【解决方案2】:

普通g表示“使用最局部的g”,::g表示使用全局的g

更一般地说,example::g 表示“使用命名空间示例中的 g”。

另外,如果你能以某种方式避免它(你通常可以),不要使用全局变量,也不要使用这样的诡计,这很容易出错。

【讨论】:

    【解决方案3】:

    Static variables are in a category of their own:它们实际上并不在“堆栈”或“堆”上。进程内存空间的特定部分用于保存与堆栈或堆不同的静态变量。有关完整讨论,请参阅给出的链接。

    您仍然可以像使用其他任何变量一样使用此变量,并且您确实可以获取指向它的指针并通过指针更改其值。

    正如其他人所建议的,不要对此感到太兴奋:global variables are frowned upon。它们通常是设计不佳的标志,并且存在许多现实世界的缺点和陷阱。

    【讨论】:

      【解决方案4】:

      通过在变量或函数前面加上::,您告诉编译器它应该在全局命名空间中查找该变量/函数,即在函数范围之外。

      【讨论】:

      • OP 的问题更多是关于静态变量的性质,而不是 :: 运算符。
      【解决方案5】:

      :: 是范围解析运算符。如果您在 foo 命名空间中声明了一些 bar 标识符,则可以使用 foo::bar 来表示它。如果您的范围解析运算符前面没有任何内容,则它表示全局命名空间。这就是为什么::g 引用全局命名空间中的g

      它获取存储在 main 之外的变量,但是该内存存储在哪里(堆栈/堆)?我们可以通过指针改变那个“全局”变量的值吗?

      我不确定为什么会出现这些问题。他们正在使用全局变量g,就像没有声明本地g 一样。需要:: 的唯一原因是因为有两个g 标识符。你可以用它做任何你可以用任何其他具有相同类型的对象做的事情。

      【讨论】:

      • OP 的问题更多是关于静态变量的性质,而不是 :: 运算符。
      【解决方案6】:

      C++ 中的:: 称为作用域解析运算符。它在许多地方都有记录(例如here)。它提供了一种命名变量的方法,这些变量可能在与当前代码不同的范围内。在:: 前面有一个可选的范围规范(例如A::g,对于命名空间A);没有范围规范指示“全局”范围。您可以对变量执行的任何操作(包括通过指针进行修改)都可以使用具有范围解析运算符的变量完成。变量所在的位置由它定义的范围定义。

      静态变量(全局或非全局变量)位于几个位置之一,这取决于编译器,也可能取决于它们的初始化方式。例如,请参阅this thread

      【讨论】:

      • OP 的问题更多是关于静态变量的性质,而不是 :: 运算符。
      • @dvnrrs - 你从哪里得到这个想法?来自 OP 的问题:“我的问题是“::(variable)”语法究竟是如何工作的?”
      • 是的;然后他继续说“它获取存储在主外部的变量,但是该内存存储在哪里(堆栈/堆)?”
      • @dvnrrs - 好点。我添加了一些关于全局变量存储的内容。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 1970-01-01
      • 1970-01-01
      • 2022-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多