2014-09-18 5 views
1

Я написал простой код c, который показан ниже. В этом фрагменте кода я хочу проверить, где хранится строка const abcd. Я сначала предполагаю, что он должен быть сохранен в разделе .data только для чтения. Однако после теста в Debian все отличается от того, что я уже догадался. Проверяя код сборки, сгенерированный gcc, я обнаружил, что он помещен в стек кадров функции p. Но когда я попробую позже в OSX, строка снова будет сохранена в разделе .data. Теперь я смущен этим. Есть ли какой-либо стандарт для хранения строки const?Где хранится const string? в стеке или .data?

#include<stdio.h> 
char *p() 
{ 
    char p[] = "abcd"; 
    return p; 
} 

int main() 
{ 
    char *pp = p(); 
    printf("%s\n",pp); 
    return 0; 
} 

UPDATE: ответ RICI в пробуждают меня. В OSX начальный литерал хранится в .data, а затем перемещается в стек стека функции позже. Таким образом, она становится локальной переменной для этой функции. Однако gcc в Debian обрабатывает эту ситуацию, отличную от OSX. В Debian gcc непосредственно хранит литерал в стеке вместо того, чтобы перемещать его с .data. Прошу прощения за мою небрежность.

+2

Реализация должна решить, где хранить литералы –

+3

Вы возвращаете указатель на локальный массив, который в любом случае является неопределенным поведением. – 5gon12eder

+0

И FWIW, я не верю вам, когда вы заявляете, что литерал хранится в кадре стека. –

ответ

0

Существует огромная разница между:

const char s[] = "abcd"; 

и

const char* t = "abcd"; 

Первый из них декларирует s быть объектом массива инициализируется из строки "ABCD". s будет иметь адрес, отличный от адреса другого объекта в программе. Сама строка символов может быть артефактом времени компиляции; инициализация - это копия, поэтому символьная строка не должна присутствовать во время выполнения, если компилятор может найти другой способ выполнения инициализации (например, немедленную операцию хранилища).

Вторая декларация объявляет t указателем на константу строки. Строковая константа теперь должна присутствовать во время выполнения, так как выражения, такие как t+1, которые являются указателями внутри строки, действительны. Стандарт языка не гарантирует, что каждое вхождение строковых литералов в программе уникально и не гарантирует, что все вхождения объединены (хотя хорошие компиляторы будут пытаться сделать второй). Однако он гарантирует, что у них есть статическое время жизни ,

Следовательно, это неопределенное поведение, так как время жизни массива s заканчивается, когда функция возвращает:

const char *gimme_a_string() { 
    const char s[] = "abcd"; 
    return s; 
} 

Тем не менее, это хорошо:

const char *gimme_a_string() { 
    const char *s = "abcd"; 
    return s; 
} 

также:

const char s[] = "abcd"; 
const char t[] = "abcd"; 
printf("%d\n", s == t); 

гарантирует печать 0, в то время как

const char* s = "abcd"; 
const char* t = "abcd"; 
printf("%d\n", s == t); 

может печатать либо 0 или 1, в зависимости от реализации. (Как написано, он почти наверняка напечатает 1.Однако, если два заявления находятся в отдельных единицах компиляции и LTO не позволит, вероятно, печатать 0)

Поскольку форма массива инициализируется копией неконстантная версия нормально:.

char s[] = "abcd"; 
s[3] = 'C'; 

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

// Will produce a warning on most compilers with compile option -Wall or equivalent 
char* s = "abcd"; 
// *** UNDEFINED BEHAVIOUR *** Can cause random program breakage 
s[3] = 'C'; 

Технически неконстантная декларация s является законным (поэтому компилятор только предупреждает), потому что это попытка изменить константу, которая является UB. Но вы всегда должны прислушиваться к предупреждениям компилятора; лучше думать об объявлении/инициализации как о неправильном, потому что это так.

1

в вашем случае, он находится в стеке. и возврат указателя на главный приведет к неопределенному поведению. но, если у вас есть static char p[] = "abcd"; или char *p = "abcd";, они (данные) находятся в .data.

+0

'p' должен быть указателем на const, поскольку вы не можете изменить этот строковый литерал. – edmz

+0

@black .rodata загружается с .data, поэтому я предполагаю, что .rodata - это своего рода сегмент .data, по крайней мере, в ELF. исправьте меня, если я ошибаюсь. – HuStmpHrrr

 Смежные вопросы

  • Нет связанных вопросов^_^