Рассмотрим эту программу на C
#include <stdio.h>
#define TOTAL_ELEMENTS (sizeof(arr))/sizeof(arr[0])
int arr[] = {23, 34, 12, 17, 204, 99, 16};
int main() {
int d;
printf("%zu\n", TOTAL_ELEMENTS);
for (d = -1; d <= (TOTAL_ELEMENTS - 2); d++) {
printf("%d ", arr[d + 1]);
}
return 0;
}
компиляторы выдают результат как 7
согласно моим пробным прогонам и рассуждениям вывод должен быть
7
23 34 12 17 204 99 16
Теперь, чтобы увидеть, что происходит не так, я применил некоторые вариации. рассмотрите этот код
#include <stdio.h>
#define TOTAL_ELEMENTS (sizeof(arr))/sizeof(arr[0])
int arr[] = {23, 34, 12, 17, 204, 99, 16};
int main() {
int d;
printf("%zu\n", TOTAL_ELEMENTS);
for (d = -1; d <=(int) ((TOTAL_ELEMENTS) - 2); d++) {
printf("%d ", arr[d + 1]);
}
return 0;
}
Обратите внимание: единственное изменение, которое я сделал, — это введение приведения типов с помощью int, и теперь оно дает ожидаемые результаты.
Теперь, насколько я знаю, когда мы сравниваем в программе C, она может правильно выполнять преобразование в больший тип данных, поэтому предположим, что TOTAL_ELEMENT даже имеет больший тип, например long, тогда d должен быть преобразован в long, и программа должна работать нормально, но этого не происходит. Какие моменты мне здесь не хватает?
@AllanWind большое спасибо, это проясняет мои сомнения: здесь мы сравниваем беззнаковые числа со знаком, что означает, что знак будет преобразован в огромное число в соответствии с беззнаком, а условие будет ложным, верно?
У @chux-ReinstateMonica op было несколько комментариев после того, как я написал ответ, поэтому я хотел перейти к обсуждению ответа. Не беспокойся. Я уже удалил остальные свои комментарии, которые больше не были полезны, так что потерять еще один не проблема. Я тоже удалю этот комментарий, если вы проголосуете за него. Попробуй :-).
В сравнении d <= (TOTAL_ELEMENTS - 2)
ранг d
ниже ранга (TOTAL_ELEMENTS - 2)
, поскольку int
имеет меньшую точность, чем size_t
на вашей платформе согласно 6.3.1.1:
Ранг целочисленного типа со знаком должен быть выше ранга любого целочисленного типа со знаком меньшей точности.
Компилятор преобразует int d = -1
в size_t
, что дает очень большое число (SIZE_MAX
из stdint.h), поэтому условие цикла является ложным и тело цикла никогда не выполняется.
size_t d
, какой тип соответствует типу вашей верхней границы.()
правую часть макроса и каждый аргумент макроса, чтобы избежать сюрпризов.d
в цикле for
.%zu
для size_t
.{}
вокруг тела цикла только в том случае, если в нем больше одного оператора, а return 0
используется по умолчанию, поэтому я исключил оба.#include <stdio.h>
#define TOTAL_ELEMENTS (sizeof (arr) / sizeof *(arr))
int main() {
int arr[] = {23, 34, 12, 17, 204, 99, 16};
printf("%zu\n", TOTAL_ELEMENTS);
for (size_t d = 0; d < TOTAL_ELEMENTS; d++)
printf("%d ", arr[d]);
}
и вы получите ожидаемый результат:
7
23 34 12 17 204 99 16
Мы можем получить ответ, если допустим, поместим d только как int и приведем TOTAL_ELEMENTS к int, верно?
@BhargavPatil Использование int
только ОК здесь в примере кода, поскольку размер массива небольшой, но в целом положительный диапазон int
является подмножеством диапазона size_t
, поэтому использование более широкого диапазона size_t
предпочтительнее.
Да, но это сложно... у вас отсутствует () в правой части макроса TOTAL_ELEMENTS
(в отличие от моего), поэтому (int) TOTAL_ELEMENTS - 2
не работает, поэтому вам нужен либо (int) (TOTAL_ELEMENTS) - 2
, либо (int) (TOTAL_ELEMENTS - 2)
. Вы используете макрос дважды, поэтому, вероятно, захотите привести его в оба места и обновить строку формата до %d
. Что читабельнее: d < TOTAL_ELEMENTS
или d <= (int) (TOTAL_ELEMENTS - 2)
. Даже если вы предпочитаете последнее, все остальные ожидают первого. sizeof(int)
, вероятно, меньше, чем sizeof(size_t)
, поэтому вы рискуете обрезать верхнюю границу.
@chux-ReinstateMonica, Аллан Винд, спасибо, это проясняет многие сомнения.
Пожалуйста, внесите изменения, чтобы уточнить вопрос, на который вы хотите получить ответ.