Начальное значение массива int в C - почему? - PullRequest
3 голосов
/ 03 июля 2019

Почему значение

int array[10];

не определено при объявлении в функции и инициализируется 0 при объявлении как static?

Я читал ответ этот вопрос и ясно, что

[выражение int array[10];] в функции означает: взять в свои руки область памяти размером 10 int без какой-либо инициализации,Если массив объявлен как глобальный или как статический в функции, то все элементы инициализируются нулями, если они еще не инициализированы.

Вопрос : почему этоповедение?Решают ли это программисты компилятора (по определенной причине)?Может ли определенный используемый компилятор делать вещи по-другому?

Почему я спрашиваю это: Я задаю этот вопрос, потому что я хотел бы сделать свой код переносимым среди архитектур / компиляторов.Чтобы это гарантировать, я знаю, что всегда могу инициализировать объявленный массив.Но это значит, что я потеряю драгоценное время только на эту операцию.Итак, какое решение является правильным?

Ответы [ 4 ]

6 голосов
/ 03 июля 2019

Автоматический int array[10]; не является неявно обнуленным, потому что обнуление требует времени, и вам может не потребоваться обнуление.Кроме того, вы платите стоимость не один раз, а каждый раз, когда элемент управления запускается после инициализированной переменной.

Статический / глобальный int array[10]; неявно обнуляется, поскольку статические / глобальные переменные размещаются ввремя загрузки.Память будет свежей от ОС, и, если ОС вообще заботится о безопасности, она будет уже обнулена.В противном случае код загрузки (ОС или динамический компоновщик) должен будет обнулить их (поскольку этого требует стандарт C), но он должен быть в состоянии сделать это за один вызов memset для всех глобальных переменных / статики, что значительноболее эффективно, чем обнуление каждой статической / глобальной переменной одновременно.

Эта инициализация выполняется один раз.Даже static s внутри функций инициализируются только один раз, даже если они имеют ненулевые инициализаторы (например, static int x = 42;. Вот почему C требует, чтобы инициализатор статического элемента был постоянным выражением).

Так какОбнуление времени загрузки всех глобальных / статических данных либо гарантировано ОС, либо эффективно реализуемо, оно также может быть гарантировано стандартом и тем самым облегчает жизнь программистов.

4 голосов
/ 03 июля 2019

Значения не являются неопределенными, но являются неопределенными, и он ведет себя так, потому что стандарт так говорит.

Раздел 6.7.9p10 C стандарта относительно состояний инициализации:

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

  • , если он имеет тип указателя, он инициализируется нулевым указателем;
  • , если он имеет арифметикутип, он инициализируется равным (положительному или без знака) нулю;
  • если он является агрегатом, каждый элемент инициализируется (рекурсивно) в соответствии с этими правилами, а любое заполнение инициализируется нулевыми битами;
  • если это объединение, первый именованный элемент инициализируется (рекурсивно) в соответствии с этими правилами, а любое заполнение инициализируется нулевыми битами;

То есть для любой переменной, определенной в файлеscope или static можно смело предположить, что значения инициализируются нулями.Для переменных, объявленных внутри функции или области, вы не можете делать какие-либо предположения о неинициализированных переменных.

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

3 голосов
/ 03 июля 2019

Причиной отсутствия определения начального значения переменных в локальных / локальных переменных является эффективность.Стандарт C ожидает, что ваша программа выделит ваш массив и позже заполнит его:

int array[10];
for (i = 0; i < 10; ++i)
    array[i] = i * 42;

В этом случае любая инициализация будет бессмысленной, поэтому стандарт C хочет этого избежать.

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

int array[10] = {0}; // initialize to zero so the accumulation below works
while (condition)
{
    ... // some code
    for (i = 0; i < 10; ++i)
        array[i] += other_array[i];
}

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

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

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

1 голос
/ 03 июля 2019

Философия C состоит в том, чтобы а) всегда доверять программисту и б) отдавать приоритет скорости выполнения над удобством программиста.C предполагает, что программист находится в лучшем положении, чтобы знать, нужно ли массиву (или любой другой переменной auto) инициализироваться определенным значением, и, если это так, достаточно умен для написания кодасделать это самим.В противном случае это не приведет к потере циклов ЦП.

То же самое для проверки границ при доступе к массиву, то же самое для NULL проверок разыменования указателей и т. Д.

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

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