Что не так с последующим кодом C?
419 просмотра
3 ответа
Возможный Дубликат:
Запутанный о расширении макроса C и целочисленной арифметике
Загадка A (в C)
Ожидаемый результат следующей C- программы - распечатать элементы в массиве. Но когда на самом деле работает, это не так.
#include<stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main()
{
int d;
for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);
return 0;
}
Автор: Parag
Источник
Размещён: 12.11.2019 09:40
Ответы (3)
6 плюса
Потому что sizeof
дает вам беззнаковое значение, которое вы , вероятно , заметили бы , если бы вы оказались уровень предупреждения, например, используя -Wall -Wextra
с gcc
(а) :
xyzzy.c: In function 'main':
xyzzy.c:8: warning: comparison between signed and unsigned
Если вы заставите его подписать, он работает нормально:
#define TOTAL_ELEMENTS (int)((sizeof(array) / sizeof(array[0])))
То, что происходит в деталях, можно почерпнуть из стандарта ISO. В сравнении между различными типами, продвижения сделаны, чтобы сделать типы совместимыми. Выбранный совместимый тип зависит от нескольких факторов, таких как совместимость знаков, точность и ранг, но в этом случае считалось, что неподписанный тип size_t
был совместимым типом, поэтому он d
был обновлен до этого типа.
К сожалению, приведение -1
к типу без знака (по крайней мере, для дополнения до двух, которое почти наверняка используется вами) приводит к довольно большому положительному числу.
Тот, который, конечно, больше, чем 5
вы получаете (TOTAL_ELEMENTS-2)
. Другими словами, ваше заявление фактически становится:
for (d = some big honking number way greater than five;
d <= 5;
d++
) {
// fat chance of getting in here !!
}
(а) Это требование использования extra
остается предметом спора между gcc
разработчиками и мной. Очевидно, они используют какое-то новое определение слова «все», о котором я раньше не знал (с извинениями перед Дугласом Адамсом).
0 плюса
TOTAL_ELEMENTS
имеет тип size_t
, вычитание 2 выполняется во время компиляции, и так оно и есть 5UL
(акцент на суффикс без знака). Сравнение с подписанным целым числом d
тогда всегда ложно. Пытаться
for(d=-1;d <= (ssize_t)(TOTAL_ELEMENTS-2);d++)
FTW, компилятор Intel предупреждает об этом точно, когда вы пытаетесь скомпилировать код.
Автор: hroptatyr Размещён: 28.03.2012 06:290 плюса
Чтобы выяснить, что пошло не так: sizeof () переводит в тип результата size_t
, который представляет собой целое число без знака, больше или равно unsigned int
.
Таким образом, результатом (sizeof(array) / sizeof(array[0]))
является результат в двух операндах типа size_t. Разделение производится на этих операндов size_t / size_t
. Оба операнда имеют одинаковый тип, поэтому он работает нормально. Результат деления имеет тип size_t
, то есть тип, к которому приводит TOTAL_ELEMENTS.
Следовательно, выражение (TOTAL_ELEMENTS-2)
имеет типы size_t - int
, поскольку целочисленный литерал 2
имеет тип int.
Здесь у нас есть два разных типа. Затем происходит то, что называется балансировкой (формально «обычные арифметические преобразования»), что происходит, когда компилятор обнаруживает два разных типа. Правила балансировки гласят, что если один операнд подписан, а другой - без знака, то подписанный молча, неявно преобразуется в тип без знака.
Это то, что происходит в этом коде. size_t - int
преобразуется в size_t - size_t
, затем выполняется вычитание, результат size_t
. Затем int <= size_t
преобразуется в size_t <= size_t
. Переменная d
становится без знака, и если она имеет отрицательное значение, код становится бесполезным.
Вопросы из категории :
- c Как вы форматируете unsigned long long int, используя printf?
- c What are the barriers to understanding pointers and what can be done to overcome them?
- c Как реализовать продолжения?
- c Как вы передаете функцию в качестве параметра в C?
- c Как получить список каталогов в C?
- c В чем разница между #include <filename> и #include "filename"?
- arrays Как удалить дубликаты из массива C #?
- arrays Как определить размер моего массива в C?
- arrays Каков наилучший способ конвертировать массив в хеш в Ruby
- arrays Сравнение двухбайтовых массивов в .NET
- arrays Можно ли выполнять параллельные обходы в MATLAB так же, как в Python?
- arrays Haxe итерация на динамическом
- c-preprocessor Предупреждение компилятора «Нет новой строки в конце файла»
- c-preprocessor Как проверить ОС с помощью директивы препроцессора?
- c-preprocessor Зачем использовать явно бессмысленные операторы do-while и if-else в макросах?
- c-preprocessor Как сделать символьную строку из значения макроса C?
- c-preprocessor Преобразовать токен препроцессора в строку