Я неправильно понимаю этот пример о области видимости строковых литералов? - PullRequest
0 голосов
/ 18 января 2019

Я читал об общих подводных камнях C и пришел к этой статье на каком-то известном сайте Uni . (Это вторая ссылка, которая появляется в Google).

Последний пример на этой странице:

// Memory allocation on the stack
void b(char **p) {
    char * str="print this string";
    *p = str;
}

int main(void) {
    char * s;
    b(&s);
    s[0]='j'; //crash, since the memory for str is allocated on the stack, 
              //and the call to b has already returned, the memory pointed to by str 
              //is no longer valid.
    return 0;
}

Это объяснение в комментарии заставило меня задуматься: разве память для строковых литералов не статична?

Тогда разве нет настоящей ошибки в том, что вы не должны изменять строковые литералы, потому что это неопределенное поведение? Или комментарии там верны, и мое понимание этого примера неверно?

При дальнейшем поиске я увидел этот вопрос: ссылка на символ, который вышел из области действия , и из этого вопроса я понял, что следующий код является действительным.

#include <malloc.h>
char* a = NULL;
{
    char* b = "stackoverflow";
    a = b;
}

int main() {
    puts(a);
}

Также этот вопрос согласен с другим вопросом о стековом потоке и моим мнением, но не согласен с комментарием из кода этого сайта.

Чтобы проверить это, я попробовал следующее,

#include <stdio.h>
#include <malloc.h>

void b(char **p)
{
    char * str = "print this string";
    *p = str;
}

int main(void)
{
    char * s;
    b(&s);
    // s[0]='j'; //crash, since the memory for str is allocated on the stack,
                //and the call to b has already returned, the memory pointed to by str is no longer valid.
    printf("%s \n", s);
    return 0;
}

, который, как и ожидалось, не дает ошибки сегментации.

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Нет, вы неправильно поняли причину сбоя. Строковые литералы имеют статическую длительность, что означает, что они существуют на протяжении всей жизни программы. Поскольку ваш указатель указывает на литерал, вы можете использовать его в любое время.

Причиной сбоя является тот факт, что строковые литералы доступны только для чтения. На самом деле char* x = "" является ошибкой в ​​C ++, как и должно быть const char* x = "". Они доступны только для чтения с точки зрения языка, и любая попытка изменить их приведет к неопределенному поведению.

На практике они часто помещаются в сегмент только для чтения, поэтому любая попытка изменения вызывает GPF - общий сбой защиты. Обычный ответ на GPF - это завершение программы, и это то, что вы наблюдаете в своем заявлении.

0 голосов
/ 18 января 2019

Стандарт говорит (подчеркиваю мое):

6.4.5 Строковые литералы

  1. [...] Последовательность многобайтовых символов затем используется для инициализации массива статической длительности хранения и длины, достаточной для размещения этой последовательности. [...]

  2. [...] Если программа пытается изменить такой массив, поведение не определено . [...]

0 голосов
/ 18 января 2019

Строковые литералы обычно размещаются в разделе rodata (только для чтения) в файле ELF, а в Linux \ Windows \ Mac-OS они попадают в область памяти, которая генерирует ошибку при записи.to (сконфигурировано с использованием MMU или MPU ОС при загрузке)

...