C оптимизация строковых литералов

просто проверял следующее в gdb:

char *a[] = {"one","two","three","four"}; char *b[] = {"one","two","three","four"}; char *c[] = {"two","three","four","five"}; char *d[] = {"one","three","four","six"}; 

и я получаю следующее:

 (gdb) pa $17 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"} (gdb) pb $18 = {0x80961a4 "one", 0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four"} (gdb) pc $19 = {0x80961a8 "two", 0x80961ac "three", 0x80961b2 "four", 0x80961b7 "five"} (gdb) pd $20 = {0x80961a4 "one", 0x80961ac "three", 0x80961b2 "four", 0x80961bc "six"} 

Я действительно удивлен, что указатели строк одинаковы для эквивалентных слов. Я бы подумал, что каждой строке будет выделена собственная память в стеке, независимо от того, была ли она такой же, как строка в другом массиве.

Является ли это примером какой-либо оптимизации компилятора или это стандартное поведение для объявления строк такого рода?

    2 Solutions collect form web for “C оптимизация строковых литералов”

    Он называется «объединение строк». Это необязательно в Microsoft Compilers, но не в GCC. Если вы отключите пул строк в MSVC, то «одни и те же» строки в разных массивах будут дублироваться и иметь разные адреса памяти, и поэтому потребуются дополнительные (ненужные) 50 байтов ваших статических данных.

    EDIT: gcc действительно имеет опцию, -fwritable-strings которая отключает объединение строк. Эффект этой опции двоякий: он позволяет перезаписывать строковые литералы и отключает пул строк. Таким образом, в вашем коде установка этого флага позволит сделать несколько опасный код

     /* Overwrite the first string in a, so that it reads 'xne'. Does not */ /* affect the instances of the string "one" in b or d */ *a[0] = 'x'; 

    (Я предполагаю, что ваши a , b , c и d объявлены как локальные переменные, что является причиной ваших ожиданий, связанных с стеком).

    Строковые литералы в C имеют статическую продолжительность хранения. Они никогда не выделяются «в стеке». Они всегда выделяются в глобальной / статической памяти и живут «навсегда», то есть до тех пор, пока программа работает.

    В массиве были выделены массивы a , b , c и d . Указатели, хранящиеся в этих массивах, указывают на статическую память. В этих обстоятельствах нет ничего необычного в том, что указатели одинаковы для идентичных слов.

    Будет ли компилятор объединять идентичные литералы в один, зависит от компилятора. У некоторых компиляторов даже есть опция, которая контролирует это поведение. Строковые литералы всегда доступны только для чтения (именно поэтому лучше использовать тип const char * для ваших массивов), поэтому не имеет большого значения, слиты ли они или нет, пока вы не начнете полагаться на фактический указатель значения.

    PS Просто из любопытства: даже если эти строковые литералы были выделены в стеке, почему вы ожидаете, что идентичные литералы будут «создаваться» более одного раза?

    Давайте будем гением компьютера.