【问题标题】:What's the difference between const char myStr[] = "hello" and const char* myStr = "hello" [duplicate]const char myStr[] = "hello" 和 const char* myStr = "hello" 有什么区别 [重复]
【发布时间】:2015-10-12 02:34:13
【问题描述】:

更新:
我认为这个问题与标记为可能重复的问题明显不同,因为我使用了关键字“const”。标记为重复的答案不能充分解释 const 在这些情况下的含义。在我看来, const 应该强制编译器将这两种情况同等对待,即使没有 const 它们是不同的。有关详细信息,请参阅我的问题下方的评论。

const char myStr[] = "hello"const char* myStr = "hello" 有什么区别?

当我编译前者时,编译后的程序大小比后者多 20 个字节更多,尽管这两种情况为全局变量占用相同数量的空间。编译器优化设置为“-Os”。


更新:
-就编译后的程序大小而言,static const char myStr[] = "hello"const char* myStr = "hello" 相同,这与去掉变量并直接将字符串文字"hello" 作为参数传递给函数相同。 const char myStr[] = "hello" 比刚才提到的其他情况多占用 20 个字节。 char myStr[] = "hello" 的程序大小与其“const”对应项相同。


我将此字符串传递给我编写的函数,该函数需要const char str[] 作为输入参数。

第 2 部分:需要 const char str[] 作为输入参数的函数是否与需要 const char* str 作为输入参数的函数相同?

相关(但不相同)问题

【问题讨论】:

  • 第 1 部分:您已经链接到几个回答它的答案...
  • 第 1 部分:我的链接似乎不太正确地回答它。他们基本上说后者 (char*) 是指向无法修改的字符串文字的指针,而前者 (char str[]) 是 可以 修改的字符数组。但这没有意义。如果我将它们都设为“const”,我不明白为什么编译器不认为它们 both 不能被修改,并将const char str[] 版本与const char* str 版本相同。
  • const char myStr[] = "你好"。 myStr 是一种 6 大小的 char 数组。对于 const char* myStr = "hello",myStr 是 char 类型的指针(大小可以是 4bytes 或 8bytes)。检查cpp.sh/4gzr
  • const char *myStr = "Hello"; 基本上是指static const char Hello_string[] = "Hello"; const char *myStr = &Hello_string[0];

标签: c++ string pointers arduino


【解决方案1】:
const char myStr[] = "hello";

您定义了一个包含 6 个元素(包括 '\0')的 const char 数组,即 {'h', 'e', 'l', 'l', 'o'. '\0'},它是从 c 风格的字符串文字“hello”复制而来的。

const char* myStr = "hello";  

您定义了一个 const char* 类型的指针,指向 c 风格的字符串文字“hello”。

在ideone.com上使用sizeofLIVE可以看出区别,前者大小为6,后者大小为4。

需要 const char str[] 作为输入参数的函数是否与需要 const char* str 作为输入参数的函数相同?

作为函数参数,它们是相同的,因为当您将数组传递给函数时,它会衰减为指针。但是使用const char str[] 可以更清楚地表明该函数需要一个数组,而不仅仅是一个指针(指向单个对象等)。注意如果你通过引用传递数组(即const char(&)[size]),它不会衰减为指针,并且会保留数组的大小。

【讨论】:

  • 与通过引用传递数组不完全相同,在这种情况下它不会衰减为指针,甚至可以推断出它的大小。
  • @vsoftco 我已经添加了它,作为补充说明。
【解决方案2】:

其实很简单。

const char myStr[] = "Hello, world!\n";

在这种情况下,sizeof(myStr) == 14,因为整个字符串位于堆栈中!它实际上与...相同。

const char myStr[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\n', '\0' };

现在,类似...

char myStr[] = "Hello, world!\n";

非常好,并且允许您稍后修改数组的内容。

现在,这个……

const char *myStr = "Hello, world!\n";

将为常量字符数组保留内存,即某处的"Hello, world!\n",通常在只读内存中,并将该数组的地址分配给myStr。因此,sizeof(myStr) == sizeof(const char*)

现在,这是一个棘手的问题......

char *myStr = "Hello, world!\n";

曾经(很长)一段时间,C 语言中没有const 关键字。因此,程序员记住了哪些可以修改,哪些不能修改。在这个例子中,myStr 指向的内存是可修改的,根据类型系统,但不是,根据字符串文字的规则。因此,修改*myStr 涉及未定义的行为。

现在,只有一点额外的细节。根据数组到指针的降级规则,声明const char*类型的参数与声明const char[]类型的参数是一样的。

【讨论】:

    【解决方案3】:

    const char myStr[] = "hello" 将字符串复制到缓冲区中。如果它是一个局部变量,它每次都会被压入堆栈,除非你将它设为静态,否则效率可能会降低,但你不妨只使用const char* myStr = "hello"。您可以将任一参数传递给 const char str[] 参数。

    一些编译器对字符串字面量执行字符串池优化。如果您明确要求将其存储在缓冲区中,我怀疑编译器可能不会对缓冲区使用字符串池优化。

    因此我推荐const char* myStr = "hello" 或更好的const char* const myStr = "hello"(因为它可能允许编译器优化内存中的指针变量,因为它知道它无法更改)。

    【讨论】:

      【解决方案4】:
      const char* myStr = "hello";  
      

      定义一个值为“hello”的字符串常量。

      char* myStr = "hello";  
      

      也定义了一个(只读)常量,即使没有常量,改变它也是未定义的行为。由于缺少 const,某些编译器(在某些配置中)会发出警告。

      const char myStr[] = "hello";  
      

      定义一个值为“hello”的字符串常量,同上。

      char myStr[] = "hello";  
      

      定义一个以后可以更改的数组,初始值为“hello”
      (数组大小 = hello 的长度 + 终止 0)

      是的,* 变体始终保持不变是一件令人讨厌的事情。

      做函数参数时,const char str[]const char *str是一样的。区别仅在于定义新变量时,而不是在指定参数类型等时。

      【讨论】:

      • 如果有问题,也请告诉我。
      • 不知道为什么答案被否决。赞成使分数不负。
      【解决方案5】:

      在第一种情况下,变量是一个数组,它使用 6 个字节并初始化为一个字符串。如果变量是本地的,空间将在进入函数时分配字符串的内容。

      在第二种情况下,变量是指向数组的指针,而数组位于其他位置。如果您定义两个这样的指针,它们可能指向同一个位置。如果变量是本地变量,则指针在进入函数时被初始化以指向字符串。如果你愿意,你可以稍后给指针分配一个不同的值,让它指向其他地方。

      我建议你看看反汇编。虽然编译器可以随意优化。

      传递给函数时没有任何区别。

      【讨论】:

      • 如果你对“const”感兴趣,那么在第一种情况下它指的是数组,但在第二种情况下,它指的是指针指向的内容。如果您愿意,您也可以使指针保持不变 - const char * const = "something";
      【解决方案6】:

      另一个区别:您可以将 (const) char* myStr 重新分配给不同的 char *(甚至 0),但您不能重新分配 (const) char myStr[] - 这会产生编译器错误.

      【讨论】:

      • 但是const char * const myStr = ...不能被重新分配。
      【解决方案7】:

      两者从外面看起来很相似,但实际上它们的实现方式却大不相同。在这种情况下,我认为关于一张图片价值 1000 字的老话是相当准确的,所以让我们从一对图片开始:

      第一个代表类似char const *myStr = "hello";。我们有一个本地指针名称myStr,它指向一些包含字符串hello 的常量数据。虚线表示这里发生的不是数据移动这一事实——myStr 只是指向字符串文字本身。

      第二个代表类似char const mystr[] = "hello";。这仍然在常量数据中有字符串的副本。在(例如)进入定义myStr 的函数时,该常量数据用于初始化为myStr 本身分配的本地存储。在这种情况下,实线表示确实涉及数据移动——至少在理论上,每次输入包含myStr 的函数时(假设它是在函数内部定义的),相同的数据都会复制到新分配的本地变量。

      当然,有可能像您展示的 myStrconst 数组的情况下,编译器可以实际上优化代码,因此副本不会占用放置在例行程序的每个条目上。尽管如此,它必须像一个数组,而不是一个指针。

      例如,在第一种情况下(char const *myStr = ...;),如果使用sizeof(myStr),则结果必须与sizeof(char const *) 相同(通常为4 或8)。在第二种情况下(不管任何优化)sizeof(myStr) 必须给出数组本身的大小,所以hello 将给出六个(大小包括终止的 NUL)。如果你使用不同的字符串(例如,“你好,你今天好吗?”)第一种情况不会受到影响——你仍然会得到指针的大小。第二种情况会完全改变--myStr is 字符数组本身,所以改变它包含的字符数会改变它的大小(在这种情况下为 32,如果我计算正确的话)。

      const 而言,它并没有改变任何东西。对于指向文字 (char const *myStr = "hello";) 的指针,您不再(从 C++11 开始)在没有 const 限定符的情况下创建指针。在此之前,您可以创建一个非const 指针,但您仍然必须基本上act 就好像它是const——通过该指针(或任何其他指向字符串文字)导致未定义的行为。

      使用数组 (char myStr[] = "...";),const 会阻止您修改数组的内容。如上所述,编译器可能理论上能够优化事物,因此它并没有真正在包含函数的每个条目上创建一个本地,并从常量存储中初始化该本地。实际上,它几乎无关紧要,甚至很难确定地检测到(这是允许开始使用它的大部分原因)。

      【讨论】:

        【解决方案8】:

        在我看来: 静态 const char myStr[] = "你好"; 将数组 'myStr' {sizeof(myStr) = strlen("hello") + 1} 存储在数据段中,这意味着这是一个运行时的东西。它还在程序的代码段(文本)中编译“你好”字。 静态 const char *myStr = "你好"; 在数据段中只存储一个指针 'myStr' {sizeof(myStr) = }。与程序代码段中的“hello”一词相同。

        当您尝试在函数堆栈中使用这两个时: const char myStr[] = "你好"; 意味着你从函数的堆栈中显式分配 sizeof(myStr) 内存,然后进行字符串复制的事情,而字符串复制的事情是昂贵的。 const char *myStr = "你好"; 只需分配一个指针,然后为其分配正确的地址。

        【讨论】:

          猜你喜欢
          • 2014-02-15
          • 2010-10-27
          • 2012-12-26
          • 2019-02-01
          • 2018-03-27
          • 2013-04-23
          • 1970-01-01
          • 2011-03-07
          相关资源
          最近更新 更多