Что означает {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);
}

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

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

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

struct foo
{
    char c;
    int  i;
};

foo a = {0};

Не то же самое, что:

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

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

Ответ 3

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

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

Ответ 4

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

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

Когда вы включаете строку:

SHELLEXECUTEINFO sexi = {0};

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

Ответ 5

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

char mytext[100] = {0};

Ответ 6

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

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

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

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

Для нескалярных типов (структур, массивов, объединений) {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, если он является плавающей точкой, или нулевой указатель если это указатель.

Правила аналогичны для С++.

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

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

Ответ 7

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

Ответ 8

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

struct foo bar = { 0 };

Вот пример:

check.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 будет вызван. wikipedia на .bss.

Если вы изменили код выше:

} my_zero_struct = { 0 };

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

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

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

Ответ 9

{0} - это анонимный массив, содержащий его как 0.

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

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

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