Кто-то мог объяснить различие в том, как 2 отрывка кода обрабатываются ниже? Они определенно компилируют в другой ассемблерный код, но я пытаюсь понять, как код мог бы действовать по-другому. Я понимаю, что строковые литералы брошены в постоянную память и эффективно статичны, но как это отличается от явных помех ниже?
struct Obj1
{
void Foo()
{
const char* str( "hello" );
}
};
и
struct Obj2
{
void Foo()
{
static const char* str( "hello" );
}
};
В вашей статической версии будет только одна переменная, которая будет где-то храниться, и всякий раз, когда функция выполняется, будет использоваться точно такая же переменная. Даже для рекурсивных вызовов.
Нестатическая версия будет сохраняться в стеке для каждого вызова функции и уничтожаться после каждого вызова.
Теперь ваш пример немного сложен в отношении того, что на самом деле делает компилятор, поэтому давайте сначала рассмотрим более простой случай:
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
Теперь в вашем примере у вас есть константа, поэтому значение не может быть изменено, поэтому компилятор может сыграть некоторые уловки, хотя это часто не влияет на сгенерированный код, но помогает компилятору обнаруживать ошибки. И тогда у вас есть указатель, и имейте в виду, что статика влияет на сам указатель, а не на значение, на которое он указывает. Таким образом, строка "hello" из вашего примера, скорее всего, будет помещена в сегмент .data вашего двоичного файла, и будет существовать только один раз, пока программа живет, независимо от статики.
Локальная статическая переменная инициализируется в первый раз , когда ее определение встречается, но не уничтожается при выходе из функции. Таким образом, он сохраняет свое значение между вызовами функции.
В случае const
это не так уж и полезно - по крайней мере, до тех пор, пока построение постоянного значения так же пренебрежимо с точки зрения производительности, как и назначение адреса. (Если объект const
не является постоянным выражением или выражение требует значительных ресурсов для создания - как в const Foo bar = foobar ();
, где foobar ())
может занять значительное время - разница может стать важной.)
Что действительно имеет значение, так это когда вы хотите вернуть объект по ссылке или указателю: вы не можете вернуть ссылку или указатель на локальный объект, если это не локальный статический объект. ( Спасибо Matthieu за указание на это. ) Однако, когда вы хотите использовать это, вы должны помнить, что локальная статика изначально небезопасна для потоков.
Хотя есть техническая разница, с точки зрения использования и эффекта ваши два примера идентичны.
Более подробно, использование ключевого слова static
применяется к указателю на строковый литерал, а не к самому строковому литералу. Указатель в примере 1 будет помещен в стек, указатель в примере 2 будет размещен со статическими переменными.
Я был бы удивлен, если бы они оба не были оптимизированы под одно и то же.
Я обнаружил, что некоторые компиляторы по-разному относятся к этим двум вариантам.
Версия с const char *
будет копировать данные из места, доступного только для чтения, в переменную на стеке.
Версия с static const char *
ссылается на данные в месте, доступном только для чтения (копирование не выполняется).
Я обнаружил эту разницу при просмотре ассемблерного кода функции с помощью отладчика. Я предлагаю вам либо распечатать ассемблерный код, либо просмотреть его на уровне языка ассемблера с помощью отладчика, чтобы найти точную истину.