【问题标题】:What determines whether a globally defined string is in the read-write or the read-only area of the data segment?什么决定了全局定义的字符串是在数据段的读写区还是只读区?
【发布时间】:2013-12-25 23:41:10
【问题描述】:

来自维基百科:

const char* string = "hello world" 使字符串文字 "hello world" 存储在初始化的只读区域和字符 指针变量string在初始化的read-write区。

  1. 为什么string 在使用const 修饰符声明时存储在read-write 区域中?
  2. 当字符串应该是不可变的时,为什么"hello world" 存储在只读区域?
  3. 有没有办法(在代码本身中)确定变量存储在哪个段和区域 (C99)?
  4. 为什么BSS/初始化数据段中的只读区和读写区没有分开?
  5. 如果不使用const 修饰符,上面引用的陈述是否仍然成立?如果没有,为什么不呢?

【问题讨论】:

    标签: c virtual-memory


    【解决方案1】:
    • 为什么在使用 const 修饰符声明字符串时,它会存储在读写区域中?

    这就是所有文字常量的所在。这样它们就可以在进程之间以及其他指向它们的指针之间共享。

    • 当字符串应该是不可变的时,为什么“hello world”存储在读写区域?

    指针(指向文字常量)本身可变的。 “hello world”很可能存储在全局常量中。

    • 有没有办法(在代码本身中)确定变量存储在哪个段和区域中 (C99)?

    全局变量和静态变量进入“全局变量”,局部变量和参数进入“堆栈”,malloc'ed 进入“堆”。至于全局变量,那些是 consts 的变量可能会或可能不会转到“global consts”。

    • 为什么BSS/初始化数据段中的只读区和读写区没有分开?

    通常有两个段 - 一个用于 const 数据(一个在进程之间共享),一个用于可变数据(显然不能共享)。

    • 如果不使用 const 修饰符,上面引用的语句是否仍然正确?如果没有,为什么不呢?

    在 C++ 中,所有字符串文字都是 const char*,而在 C 中,它们本质上是 char*。因此,在 C 中从 string 变量中添加/删除 const 是没有问题的(有时会发出警告),但它会导致 C++ 中的 const-cast 错误。在const char* string 中包含const 禁止修改string 的数据。

    附:以下代码可能会帮助您了解发生了什么:

    int main()
    {
        char s1[] = "abc";
        char* s2  = "abc";
        const char* s3  = "abc";
        s1[0] = 'z';
        s2[0] = 'x';
        // s3[0] = 'y'; will not compile due to const
        printf("%s %s %s\n", s1, s2, s3);
        s2++; s3++; // it perfectly fine to modify pointers themselves
    }
    

    根据平台,代码可能在 s2[0] 赋值时崩溃(Linux),或者可能成功;在以后的情况下,s3 也可能会被修改(Cygwin),也可能不会。

    【讨论】:

      【解决方案2】:

      我不太明白你想问什么。在您的示例中,"hello world" 存储在读写区域中,但 指向它的指针 没有,因为它没有被声明为 const

      const char* string 表示,这是一个可变指针,指向一个常量字符串

      要使指针也存储在只读区域中,您必须将其声明为const

      const char* const string = "hello world";
      

      常量

      我一般 C 和 C++ 语言中的所有修饰符都绑定到它的 left 的值。仅当左侧没有任何内容时,它们才适用于其右侧的下一个。因此这两个是相同的:

      char const* str; // Bind const modifier to 'char'.
      const char* str; // Bind const modifier to 'char', since there is nothing to the left.
      

      查看此内容时,您需要注意指针声明由 2 个“部分”组成。指针指向的类型,以及指针本身

      constvolatile 等修饰符可以应用于这两个部分:

      char* const str; // A constant pointer, that points to a mutable char (array).
      

      这里有几个例子,const 如何影响变量:

      char const* a = "foo";
      *a = '\0';  // Error, the array pointed to is not mutable.
      a = "bar";  // Okay.
      
      char* const b = "foo";
      *b = '\0';  // Okay.
      b = "bar";  // Error, the pointer is not mutable.
      

      【讨论】:

      • 我不知道您可以将 const 放在标识符后面。现在对我来说很有意义。谢谢!
      • 我添加了一个部分const,再给我一个;)
      【解决方案3】:

      你误会了。该字符串始终是只读的。保存指向字符串的指针的变量string 是一个可变变量,所以它必须是可重新赋值的:

      const char * string = "abc";
      
      int main()
      {
          string = NULL;    // this must work
      }
      

      此外,您应该明白,C 标准不包含关于实际程序实现细节的任何要求,特别是没有“只读内存”的概念。他们是否希望提供具有不同访问权限的不同类型的内存,这纯粹是平台(编译器、链接器、二进制格式、加载器)的选择。

      【讨论】:

      • 因此,即使您省略了 const,“abc”仍然是不可变的 - 那么添加 const 有什么意义呢?谢谢
      • @WuschelbeutelKartoffelhuhn:这基本上是一个错误,但由于历史惯性,C允许您将指向字符串文字的指针分配给char *。认为它具有历史意义。对于它的价值,C++11 解决了这个问题。字符串文字总是只读的,就是这样。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多