Инициализировать переменную до ее собственного значения undefined
В C, делает ли инициализация переменной собственной значимостью? Если да, зачем?
Позвольте мне уточнить. В источниках Git есть несколько примеров инициализации переменной значением undefined, как показано в transport.c или wt-status.c. Я удалил задания из этих объявлений и проверил тесты. Не видя регрессий, я думал, что эти задания были излишними.
С другой стороны, я провел несколько простых тестов с GCC 4.6 и Clang 2.9.
#include <stdio.h>
int main() {
printf("print to increase probability of registers being non-zero\n");
int status = status;
return printf("%i\n", status);
}
Компиляция с -Wall -std=c99
и различными уровнями -O
не выводит никаких предупреждений и показывает, что status == 0
. Тем не менее, Clang с ненулевым уровнем оптимизации печатает некоторые значения мусора. Это делает вывод о том, что результаты таких выражений undefined.
Я могу себе представить, что такое задание может подавлять предупреждение неинициализированной переменной, но это не относится к примерам, взятым из Git. Удаление назначений не вносит никаких предупреждений.
Являются ли такие назначения поведения undefined? Если нет, для чего вы их используете?
Я предложил изменение в списке рассылки Git. Вот что я узнал.
Ответы
Ответ 1
Это компилируется, потому что Стандарт C99 §6.2.1/7 говорит:
Любой идентификатор, который не является тегом структуры, объединения или перечисления, имеет область действия, которая начинается сразу после завершения ее декларатора. " За декларатором следует инициализатор.
Однако значение status
Неопределенное. И вы не можете полагаться на то, что оно инициализируется чем-то значимым.
Как это работает?
int status
создает пространство для существования переменной в стеке (локальное хранилище), которое затем считывается для выполнения status = status
, status
может быть инициализировано любым значением, которое присутствовало в фрейме стека.
Как вы можете защитить от такой самоинициализации?
gcc предоставляет конкретную настройку для обнаружения самоинициализации и сообщает об ошибках:
-Werror = uninitialized -Winit-self
Почему он используется в этом коде?
Единственная причина, по которой я могу предположить, что он используется в указанном коде, заключается в подавлении предупреждения неиспользуемой переменной для ex: In transport.c
, если элемент управления никогда не входит в цикл while
, тогда в этом потоке управления cmp
будет не используется, и компилятор должен создать для него предупреждение. Похоже, что такой же сценарий имеет переменную status
в wt-status.c
Ответ 2
Для меня единственной причиной такой инициализации с самоначислением является предотвращение предупреждения.
В случае вашего transport.c
я даже не понимаю, почему это полезно. Я бы оставил cmp
неинициализированным.
Моя собственная привычка (по крайней мере, на C) заключается в инициализации всех переменных, обычно до 0. Компилятор оптимизирует ненужную инициализацию, а все инициализируемые переменные облегчают отладку.
Есть случай, когда я хочу, чтобы переменная оставалась неинициализированной, и я могу ее самостоятельно назначить: случайные семплы:
unsigned myseed = myseed;
srand(myseed);
Ответ 3
В MacOS X 10.7.2 я попробовал этот пример - с показанным результатом...
$ cat x3.c
#include <stdio.h>
int status = -7;
int main()
{
printf("status = %d\n", status);
int status = status;
printf("status = %d\n", status);
return 0;
}
$ make x3
gcc -O -std=c99 -Wall -Wextra x3.c -o x3
$ ./x3
status = -7
status = 1787486824
$
В стеке, где локальный status
в main()
использовался printf()
, поэтому самоинициализация копирует мусор вокруг.
Ответ 4
Я думаю, что status = status
не меняет значение status
(по сравнению с int status;
). Я думаю, что он используется для подавления предупреждения unused variable
.