Разница между статическим const char * и const char * - PullRequest
14 голосов
/ 28 мая 2010

Может ли кто-нибудь объяснить разницу в том, как обрабатываются 2 фрагмента кода ниже? Они определенно компилируются в другой ассемблерный код, но я пытаюсь понять, как код может действовать по-другому. Я понимаю, что строковые литералы выбрасываются в постоянную память и фактически являются статическими, но чем это отличается от явного статического значения ниже?

struct Obj1
{
    void Foo()
    {
        const char* str( "hello" );
    }
};

и

struct Obj2
{
    void Foo()
    {
        static const char* str( "hello" );
    }
};

Ответы [ 4 ]

18 голосов
/ 28 мая 2010

В вашей статической версии будет только одна переменная, которая будет где-то храниться, и всякий раз, когда функция выполняется, будет использоваться точно такая же переменная. Даже для рекурсивных вызовов.

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

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

void foo() {
    static long i = 4;
    --i;
    printf("%l\n", i);
}

А потом главное что-то вроде этого:

int main() {
    foo();
    foo();
    return 0;
}

напечатает

3
2

, тогда как с

void foo() {
    long i = 4;
    --i;
    printf("%l\n", i);
}

будет напечатано

3
3

Теперь в вашем примере у вас есть const, поэтому значение не может быть изменено, поэтому компилятор может воспроизвести некоторые трюки, хотя это часто не влияет на сгенерированный код, но помогает компилятору обнаруживать ошибки. Кроме того, у вас есть указатель, и имейте в виду, что статика влияет на сам указатель, а не на значение, на которое он указывает. Таким образом, строка «привет» из вашего примера, скорее всего, будет помещена в сегмент .data вашего бинарного файла и всего один раз и будет жить столько, сколько длится программа, независимо от статичности.

10 голосов
/ 28 мая 2010

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

В случае const это не так уж и полезно - по крайней мере, до тех пор, пока построение постоянного значения столь же пренебрежимо мало для производительности, как присвоение адреса. (Если объект const не является константным выражением или для его создания требуется много ресурсов - как в const Foo bar = foobar();, где foobar() может занять значительное время - разница может стать важной.)

Разница в том, когда вы хотите вернуть объект по ссылке или указателю: вы не можете вернуть ссылку или указатель на локальный объект, если он не является локальным статическим объектом. ( Спасибо Matthieu за указание на это. ) Однако, когда вы хотите использовать это, вы должны иметь в виду, что локальная статика по своей природе небезопасна.

8 голосов
/ 28 мая 2010

Я обнаружил, что некоторые компиляторы относятся к ним по-разному.

Версия с const char * будет копировать данные из места только для чтения в переменную в стеке.

Версия с static const char * ссылается на данные только для чтения (копирование не выполняется).

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

2 голосов
/ 28 мая 2010

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

Более подробно, использование вами ключевого слова static относится к указателю на строковый литерал, а не к самому строковому литералу. Указатель в примере 1 будет помещен в стек, указатель в примере 2 будет помещен со статическими переменными.

Я был бы удивлен, если бы они оба не оптимизировались под одну и ту же вещь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...