stati c const char * VS const char * in C - PullRequest
2 голосов
/ 19 апреля 2020

В чем разница между const char* и static const char* в C?

Я думаю, что ответ Разница между stati c const char * и const char * неверно.

Действительно, элементы const char* помещаются в раздел .rodata программы, в противном случае следующее может привести к segfault:

const char* f() {
    const char* hello = "hello";
    return hello;
}

int main() {
    const char* hello_after = f();
    printf("%s\n", hello_after);
}

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

Но тогда, мне кажется, что const char* и static const char* - это то же самое, что касается G CC.

Но тогда почему поведение не одинаково для const int* и static const int*? Это исключение, жестко закодированное в G CC, что только для типа char тогда const и static const должны быть одинаковыми?

Большое спасибо за помощь!

Ответы [ 3 ]

4 голосов
/ 19 апреля 2020

В этом объявлении функции

const char* f() {
    const char* hello = "hello";
    return hello;
}

указатель hello указывает на строковый литерал "hello", который имеет длительность хранения c. То есть не указатель имеет длительность хранения c, а указанный литерал имеет длительность хранения c. При каждом вызове функции указатель инициализируется заново.

Если вы объявите функцию наподобие

const char* f( ) {
    static const char* hello = "hello";
    return hello;
}

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

Например, рассмотрим эту демонстрационную программу.

#include <stdio.h>

const char* f( int i ) 
{
    static const char* hello = "hello";

    if ( i == 1 ) hello = "bye";
    else if ( i == -1 ) hello = "hello";

    return hello;
}

int main(void) 
{
    puts( f( 0 ) );
    puts( f( 1 ) );
    puts( f( 0 ) );

    return 0;
}

Ее вывод

hello
bye
bye

То есть изначально указатель hello был инициализирован строковым литералом «hello».

Затем из-за этого вызова

    puts( f( 1 ) );

его значение было изменено. Теперь он указывает на строковый литерал "пока".

И для третьего вызова

    puts( f( 0 ) );

указатель сохраняет значение, которое было ему присвоено при предыдущем вызове функции.

Это связано с тем, что указатель имеет длительность хранения c.

0 голосов
/ 19 апреля 2020

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

Если функция возвращает ссылку на локальный объект, это будет неопределенное поведение.

примеры:

const char * f( ) {
    const char hello[] = "hello";
    return hello;
}

const char ** g( ) {
    const char *hello = "hello";
    return &hello;
}
0 голосов
/ 19 апреля 2020

В обоих случаях память для составляющих символов одинакова.
Разница заключается в самой переменной .

Представьте, что в f() вы звоните printf("%s\n", hello++).

Если переменная hello имеет квалификатор static, то при первом вызове f() она печатает "hello\n", во второй раз "ello\n", в третий раз "llo\n" ...

Если переменная hello не имеет квалификатора static, то она всегда будет печатать "hello\n" (и приращение становится бесполезным).

/**
  gcc -std=c99 -o prog_c prog_c.c \
      -pedantic -Wall -Wextra -Wconversion \
      -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <stdio.h>

void
f(void)
{
#if 1 // change to 0 to disable static storage of the "variable"
  static
#endif
  const char* hello = "hello";
  printf("%s\n", hello++);
}

int
main(void)
{
  f();
  f();
  f();
  return 0;
}
...