#c
#c
Вопрос:
У меня есть глобальный объект, который объявляется перед функцией main, и статический объект внутри main.
- Какой из них использует (или выполняет оба?) статическую инициализацию?
- Я слышал, что
A obj1
это также называется статическим; почему это так?
class A { ... };
A obj1;
int main()
{
static A obj2;
}
Комментарии:
1. Это похоже на домашнее задание, пожалуйста, используйте соответствующий тег.
2. почему это выглядит как домашнее задание?
3. Потому что пример выглядит как пример из учебника.
Ответ №1:
obj1
имеет статическое хранилище. Он будет инициализирован при запуске программы.
obj2
также имеет статическое хранилище, потому что вы так сказали. Он будет инициализирован при main()
первом выполнении.
Комментарии:
1. для записи: obj1 имеет статическое хранилище, поскольку он является глобальным / членом пространства имен (не связан с функцией (областью действия) или классом (экземпляром))
2. не все ли статические объекты хранилища инициализируются нулем при запуске программы?
3. @user974191: Нет, наиболее очевидным контрпримером будут строковые литералы
"such as this"
.4. @MSalters:
sec (8.5/6) Every object of static storage duration shall be zero-initialized at program startup before any other initialization takes place.
5. @MSalters: Это совсем не очевидно. Вы хотите сказать, что
static int x = 3;
это не заканчивается значением3
, потому что оно инициализируется нулем в качестве первого шага?
Ответ №2:
Мое первое сомнение заключается в том, насколько точен вопрос. Если статическая инициализация используется с техническим значением в стандарте, она представляет собой инициализацию с нулевым значением и инициализацию типа POD с постоянными выражениями для объектов с длительностью хранения, по сравнению с динамической инициализацией, где инициализация объекта со статической продолжительностью хранения инициализируется как-то иначе.
Для наглядного примера:
// at namespace level
int f();
int a; // 1 static: zero initialization
int b = 10; // 2 static: initialization from constant expression
int c = f(); // 3 static (zero initialization)
// 5 followed by dynamic (result of call to f())
int d = 20; // 4 static: initialization
int f() { return d; }
int main() {}
Число указывает порядок выполнения каждого шага инициализации. Причина, по которой компилятор рассматривает как статическую, так и динамическую инициализацию, заключается в том, что он устанавливает порядок выполнения инициализации. статическая инициализация выполняется перед динамической инициализацией, и все статически инициализированные объекты гарантированно получат свое значение до начала любой динамической инициализации. То есть стандарт гарантирует, что даже если d
появляется после c
в предыдущей программе, значение c
гарантированно равно 20
.
Для объектов, требующих динамической инициализации, они (концептуально) инициализируются нулем во время статической инициализации, поэтому в течение срока службы c
сначала устанавливается значение 0, а затем сбрасывается f()
(или 20 в этой программе). Концептуально это связано с тем фактом, что если компилятор может вывести конечное значение, которое получит переменная, он может оптимизировать динамическую инициализацию и просто выполнить простую статическую инициализацию с этим конечным значением (в приведенном выше коде компилятор может обнаружить, что c
оно будет динамически инициализироваться до 20, ирешите преобразовать его в статическую инициализацию, как int c = 20;
в соответствующей реализации. В этом случае шаги 3 и 5 в приведенном выше коде будут объединены в один шаг 3.
В случае локальной переменной со статической продолжительностью хранения стандарт не использует термины статическая/динамическая инициализация, но описания требуют такого же поведения от программы. Локальные переменные со статической длительностью инициализируются нулем или POD инициализируются с помощью постоянных выражений, когда (или до) блок вводится в первый раз (как при статической инициализации), в то время как для остальных инициализаций выполняются при первом переходе управления через его объявление.
Ответ №3:
Сосредоточив внимание только на C , вам также необходимо рассмотреть инициализацию статических членов. Это касается статических членов класса. Например, когда у вас есть:
class A {
// declaration of i as a static member of class A
static int i;
};
// initialization of static member outside class A
int A::i = 42;
Комментарии:
1. Нет, это совсем не так. То, что вы
i
являетесь членом класса, не имеет никакого отношения к его статическому поведению при инициализации, и оно не сильно отличается от случая OP.2. Я не думаю, что есть что-то неправильное в указании на то, что ключевое
static
слово применяется к членам класса в C или что эквивалент не существует для структур C. Это вопрос терминологии, поэтому, если нужно провести обзор области значения «статического», хорошо бы охватить все основы. Статические члены класса, статические методы класса и т. Д. 0,5 за упоминание об этом и 0,5 за упоминание Дугласа Адамса.3. @jHackTheRipper: Вопрос не в названии. Обратите внимание, что этот ответ полностью изменился с момента моего первоначального комментария. Сейчас это не так уж плохо, но по-прежнему не отвечает на вопрос (который вообще не касается членов класса).
4. @HostileFork: И я не понимаю, какое отношение C имеет к чему-либо, но я полагаю, что если вы дадите половину голосов только за то, что написали «42», тогда вы проголосуете за что угодно!
5. @HostileFork: В этом нет ничего разговорного, и это не расплывчатый вопрос: вопрос очень четко сформулирован (Дэвиду удалось его понять), и этот ответ не имеет к нему никакого отношения . И текущая оценка вопроса или ответа не должна иметь абсолютно никакого отношения к тому, какой голос вы отдаете. Кроме того, причина, по которой у меня 37.6k, заключается в том, что мне нечего делать, кроме как вносить конструктивный вклад в переполнение стека
Ответ №4:
Обе эти переменные являются статическими:
obj1
является нелокальной статической переменной, которая будет инициализирована при запуске программы.
obj2
это локальная статическая переменная, которая будет инициализирована при первом вызове функции.
Скотт Мейерс в своей книге «Эффективный C » рекомендует обращаться к локальным статическим переменным через функции, а не использовать нелокальные статические переменные. Это позволяет избежать так называемой проблемы со статическим порядком инициализации, когда одна переменная может ссылаться на другую, которая, возможно, еще не была инициализирована из-за произвольного порядка, в котором происходит инициализация.
Комментарии:
1. 1 «Фиаско порядка статической инициализации» parashift.com/c -faq-lite/ctors.html#faq-10.14