Подтвердить что ты не робот

Инициализировать переменную до ее собственного значения 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. Вот что я узнал.

4b9b3361

Ответ 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.