Что означает {0} при инициализации объекта?

, когда {0} используется для инициализации объекта, что это значит? Я не могу найти никаких ссылок на {0} в любом месте, и из-за фигурных скобок поиск Google не помогает.

пример кода:

SHELLEXECUTEINFO sexi = {0}; // what does this do?
sexi.cbSize = sizeof(SHELLEXECUTEINFO);
sexi.hwnd = NULL;
sexi.fMask = SEE_MASK_NOCLOSEPROCESS;
sexi.lpFile = lpFile.c_str();
sexi.lpParameters = args;
sexi.nShow = nShow;

if(ShellExecuteEx(&sexi))
{
    DWORD wait = WaitForSingleObject(sexi.hProcess, INFINITE);
    if(wait == WAIT_OBJECT_0)
        GetExitCodeProcess(sexi.hProcess, &returnCode);
}

без него приведенный выше код будет сбой во время выполнения.

9 ответов


что здесь происходит называется совокупность инициализации. Вот (сокращенное) определение агрегата из раздела 8.5.1 спецификации ISO:

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

теперь, используя {0} инициализировать агрегат, как это в основном трюк для 0 в вся вещь. Это связано с тем, что при использовании aggregate initialization вам не нужно указывать всех членов и спецификация требует, чтобы все неуказанные члены были инициализированы по умолчанию, что означает значение 0 для простых типов.

вот соответствующая цитата из спецификации:

если в списке меньше инициализаторов, чем членов в совокупности, то каждый член не явно инициализируется по умолчанию-инициализировать. Пример:

struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };

инициализирует ss.a С 1, ss.b С "asdf" и ss.c со значением выражение вида int(), то есть, 0.

вы можете найти полную спецификацию на эту тему здесь


следует помнить, что этот метод не будет устанавливать байты заполнения на ноль. Например:

struct foo
{
    char c;
    int  i;
};

foo a = {0};

- это не то же, что:

foo a;
memset(&a,0,sizeof(a));

в первом случае байты pad между c и i неинициализированы. Зачем вы заботитесь? Ну, если вы сохраняете эти данные на диск или отправляете их по сети или что-то еще, у вас может быть проблема с безопасностью.


обратите внимание, что пустой агрегатный инициализатор также работает:

SHELLEXECUTEINFO sexi = {};
char mytext[100] = {};

в ответ на то, почему ShellExecuteEx() рушится: ваш SHELLEXECUTEINFO структура "sexi" имеет много членов, и вы только инициализируете некоторые из них.

например, может указывать куда угодно, но ShellExecuteEx() все равно попытается использовать его, поэтому вы получите нарушение доступа к памяти.

при включении строки:

SHELLEXECUTEINFO sexi = {0};

перед остальной частью настройки структуры вы говорите компилятору обнулить все элементы структуры перед вы инициализируете те, которые вас интересуют. ShellExecuteEx() знает, что если sexi.lpDirectory равно нулю, он должен игнорировать его.


Я также использую его для инициализации строк, например.

char mytext[100] = {0};

{0} является допустимым инициализатором для любого (полного объекта) типа как на C, так и на C++. Это обычная идиома, используемая для инициализации объекта в ноль (читайте дальше, чтобы увидеть, что это означает).

для скалярных типов (арифметических и указательных типов) фигурные скобки не нужны, но они явно разрешены. Цитируя проект N1570 стандарта ISO C, раздел 6.7.9:

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

он инициализирует объект до нуля (0 для целых чисел, 0.0 для операций с плавающей запятой, указатель null для указателей).

для не скалярных типов (структур, массивов, объединений),{0} указывает, что первый элемент объекта инициализируется до нуля. Для структур, содержащих структуры, массивы структур и так далее, это применяется рекурсивно, поэтому первый скалярный элемент имеет значение ноль в зависимости от типа. Как и в любом инициализаторе, все элементы, не указанные, равны нулю.

промежуточный скобки ({, }) может быть опущено; например, оба они действительны и эквивалентны:

int arr[2][2] = { { 1, 2 }, {3, 4} };

int arr[2][2] = { 1, 2, 3, 4 };

вот почему вам не нужно писать, например,{ { 0 } } для типа, первый элемент которого является скаляр.

значит так:

some_type obj = { 0 };

- это сокращенный способ инициализации obj до нуля, что означает, что каждый скаляр суб-объект obj установлено значение 0 если это целое число, 0.0 если это плавающая точка или нулевой указатель, если это указатель.

правила аналогичны для C++.

в вашем конкретном случае, так как вы присваиваете значения sexi.cbSize и так далее, ясно, что SHELLEXECUTEINFO является структурой или типом класса (или, возможно, объединением, но, вероятно, нет), поэтому не все это применимо, но, как я сказал { 0 } является общей идиомой, которая может использоваться в более общем положения.

это не (обязательно) эквивалентно использованию memset чтобы установить представление объекта в all-bits-zero. Ни плавающей точки 0.0 ни нулевой указатель не обязательно представлен как all-bits-zero, а { 0 } инициализатор не обязательно устанавливает байты заполнения в любое конкретное значение. В большинстве систем, однако, это, вероятно, будет иметь тот же эффект.


прошло некоторое время с тех пор, как я работал в c/C++, но IIRC, тот же ярлык можно использовать и для массивов.


я всегда удивлялся, почему вы должны использовать что-то вроде

struct foo bar = { 0 };

вот тестовый пример, чтобы объяснить:

проверка.c

struct f {
    int x;
    char a;
} my_zero_struct;

int main(void)
{
    return my_zero_struct.x;
}

я компилирую с gcc -O2 -o check check.c а затем выведите таблицу символов с readelf -s check | sort -k 2 (это с gcc 4.6.3 на ubuntu 12.04.2 в системе x64). Отрывок:

59: 0000000000601018     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
48: 0000000000601018     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
25: 0000000000601018     0 SECTION LOCAL  DEFAULT   25 
33: 0000000000601018     1 OBJECT  LOCAL  DEFAULT   25 completed.6531
34: 0000000000601020     8 OBJECT  LOCAL  DEFAULT   25 dtor_idx.6533
62: 0000000000601028     8 OBJECT  GLOBAL DEFAULT   25 my_zero_struct
57: 0000000000601030     0 NOTYPE  GLOBAL DEFAULT  ABS _end

важно здесь то, что my_zero_struct после __bss_start. Этот." раздел " bss " в программе на C - это раздел памяти который установлен в ноль до main называется see Википедии .bss.

если вы измените код, чтобы:

} my_zero_struct = { 0 };

тогда результирующий исполняемый файл "check" выглядит ровно то же самое, по крайней мере, с компилятором gcc 4.6.3 на ubuntu 12.04.2;my_zero_struct еще в .bss раздел и, таким образом, он будет автоматически инициализирован до нуля, прежде чем main называется.

намеки в комментариях, что а memset может инициализировать" полную " структуру также не является улучшением, потому что .bss раздел очищается полностью, что также означает, что" полная " структура установлена на ноль.

это может быть может, стандарт языка C не упоминает ничего из этого, но в реальном мире компилятор C я никогда не видел другого поведения.


{0} является анонимный массив содержит свой элемент как 0.

Это используется, чтобы инициализировать один или все элементы массива с 0.

например int arr[8] = {0};

в этом случае все элементы arr будут инициализированы как 0.