C++ 数组中的相同字符串具有相同的内存地址

C++ 数组中的相同字符串具有相同的内存地址,c++,arrays,memory,string-literals,C++,Arrays,Memory,String Literals,为什么char*数组中的相同字符串具有相同的地址 这是因为编译器优化吗 例如: #include <stdio.h> #include <stdlib.h> #include <string.h> #define ARR_SIZE 7 int main(int argc, char** argv) { size_t i = 0, j = 0; char * myArr[ARR_SIZE] = { "This is the first st

为什么char*数组中的相同字符串具有相同的地址

这是因为编译器优化吗

例如:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ARR_SIZE 7

int main(int argc, char** argv) {
  size_t i = 0, j = 0;

  char * myArr[ARR_SIZE] = {
    "This is the first string",
    "This is the second string",
    "This is Engie",
    "This is the third string",
    "This is Engie",
    "This is the fifth string",
    "This is Engie"

  };

  for (i = 0; i < ARR_SIZE; ++i){
    for (j = i + 1; j < ARR_SIZE; ++j){
      if (memcmp((myArr + i), (myArr + j), sizeof(char*)) == 0){
      fprintf(stdout, "%p, %p\n", *(myArr + i), *(myArr + j));
      fprintf(stdout, "found it start index: %lu, search index: %lu\n", i, j);
      }
    }
  }
  return 0;
}

这称为常数合并。它通常在更高级别的优化中启用。编译器只需获取所有唯一的常量值并对其进行压缩。有利于提高内存使用率和缓存效率

gcc具有
-fmerge常量
或使用-O和company

其他编译器可能会也可能不会这样做。它是特定于编译器的

因为它是最容易实现的优化操作,我想所有C++编译器都会执行它。 这是一个完美的例子,说明了为什么:

  • 您不能假设常量值将存在于何处(未定义的行为)
  • 不应更改常量值(未定义的行为)

  • 但是我们看到很多关于人们(不是你自己)的问题,他们观察到他们在丢弃常量之后修改了常量字符串。

    我猜这确实是因为优化,这很可能没有违反
    规则,因此,他优化了无用的副本。语言标准明确允许这样做。请理解,带引号的字符串是基本上存储在方法指令流附近的文本。它们占用编译模块中的物理空间。它们(表面上)也是“恒定的”,不应该被改变,即使系统在物理上没有阻止修改。所以复制它们是没有意义的。值得注意的是,这甚至发生在Java中,在Java中,字符串文本被“插入”,因此堆中只存在每个唯一值的一个副本。(但请注意,我说的是“文字”。)与我一直知道类似的事情正在发生,不知道它叫什么。谢谢。从const char*中去掉constness会调用UB,所以他们可能会使用它,但是当他们试图在其他地方运行代码时,它可能会使他们的系统崩溃program@Creris我想知道你是否尝试了整个程序的优化,它是否启用了它?(我在回复你的其他评论,哎呀)实际上我对代码的观察很差。因为数组似乎只有在使用时才会被初始化,而且我在第一次使用之前创建了断点,所以它没有显示任何变量。但是当涉及到打印时,当我打印地址时,它确实不允许它优化它,即使使用/Ox
    
    (gdb) x/7w myArr
    0x7fffffffdd10: U"\x4007a8"
    0x7fffffffdd18: U"\x4007c1"
    0x7fffffffdd20: U"\x4007db"
    0x7fffffffdd28: U"\x4007e9"
    0x7fffffffdd30: U"\x4007db"
    0x7fffffffdd38: U"\x400802"
    0x7fffffffdd40: U"\x4007db"
    
    
    (gdb) x/7s *myArr
    0x4007a8:   "This is the first string"
    0x4007c1:   "This is the second string"
    0x4007db:   "This is Engie"
    0x4007e9:   "This is the third string"
    0x400802:   "This is the fifth string"
    0x40081b:   "%p, %p\n"
    0x400823:   ""