В общем, вы правы, вы не должны игнорировать предупреждения! И вообще, если можно, вы должны уклоняться от явных бросков, потому что они могут сделать ваш код менее надежным, или предупреждение о молчании, которое действительно пытается рассказать вам что-то важное.
В большинстве случаев, я считаю, компилятор должен поступать правильно для вас. Например, malloc()
ожидает size_t
, и компилятор знает, от прототипа функции, что он делает, так что если вы пишете
int size_i_need = 10;
char *buf = malloc(size_i_need);
компилятор вставит соответствующее преобразование из междунар в size_t, по мере необходимости. (Я не думаю, что у меня были предупреждения, о которых мне тоже приходилось беспокоиться.)
Если переменные, которые вы используете, уже unsigned
, тем лучше!
Точно так же, если вы напишете
fgets(buf, sizeof(buf), ifp);
компилятор снова вставить в соответствующее преобразование. Здесь, я думаю, я вижу, что вы получаете, 64-битный компилятор может выдать предупреждение о преобразовании down из long в int. Теперь, когда я думаю об этом, я не уверен, почему у меня не было этой проблемы, потому что это распространенная идиома.
(Вы также задан вопрос о переходе unsigned long
к malloc
, и на машине, где size_t
меньше, чем long
, я полагаю, что могли бы получить предупреждения, тоже. Это то, что вы были обеспокоены?)
Если вы у вас есть сокращение, которого вы не можете избежать, и ваш компилятор или какой-либо другой инструмент предупреждают об этом, и вы хотите избавиться от предупреждения safely, вы можете использовать бросок и утверждение. То есть, если вы пишете
unsigned long long size_i_need = 23;
char *buf = malloc(size_i_need);
это может получить предупреждение на машине, где size_t - 32 бит. Таким образом, вы можете отключить предупреждение с броском (в предположении, что ваши неподписанные длинные длинные значения никогда не будет на самом деле быть слишком большим), а затем создать резервную копию предположения с призывом assert
:
unsigned long long size_i_need = 23;
assert(size_i_need <= SIZE_MAX);
char *buf = malloc((size_t)size_i_need);
По моему опыту, самая большая неприятность печатает эти вещи. Если вы пишете
printf("int size = %d\n", sizeof(int));
или
printf("string length = %d\n", strlen("abc"));
на 64-битной машине, современный компилятор обычно (и правильно) предупреждают, что «формат определяет тип„Int“, но аргумент имеет тип" unsigned long '", или что-то в этом роде. Вы можете исправить это двумя способами: бросить значение в соответствии с форматом PRINTF или изменить формат PRINTF, чтобы соответствовать значению:
printf("int size = %d\n", (int)sizeof(int));
printf("string length = %lu\n", strlen("abc"));
В первом случае, вы в предположении, что результат sizeof
«s будет соответствовать в int (что, вероятно, является безопасной ставкой). Во втором случае вы предполагаете, что size_t
- это фактически unsigned long
, что может быть истинным в 64-битном компиляторе, но может быть неверным для некоторых других. Так что на самом деле безопаснее использовать явное приведение во втором случае тоже:
printf("string length = %lu\n", (unsigned long)strlen("abc"));
Суть заключается в том, что абстрактные типы как size_t
не работают так хорошо с printf
; это то, где мы можем видеть, что стиль вывода C++ cout << "string length = " << strlen("abc") << endl
имеет свои преимущества.
Чтобы решить эту проблему, есть некоторые специальные printf
модификаторы, которые гарантированно соответствуют size_t
, и я думаю, что off_t
и несколько других абстрактных типов, хотя они не так хорошо известны. (Я не был уверен, где их искать, но пока я сочиняю этот ответ, некоторые комментаторы уже напомнили мне.) Так что лучший способ распечатать одну из этих вещей (если вы помните, повторное использование старых компиляторов) будет
printf("string length = %zu\n", strlen("abc"));
Итог:
- Вы, очевидно, не придется беспокоиться о прохождении простой
int
или простой unsigned
к функции как calloc
, ожидающей size_t
.
- При вызове то, что может привести к подавленным, например, пропусканием
size_t
к fgets
где size_t
составляет 64 бита, но int
32, или проходя unsigned long long
к calloc
где size_t
только 32 бита, вы можете получить предупреждение. Если вы не можете сделать переданные типы меньшими (что в общем случае вы не сможете сделать), у вас будет мало выбора, чтобы заставить замолчать предупреждения, но вставить бросок. В этом случае, чтобы быть строго правильным, вы можете добавить некоторые утверждения.
Со всем сказанным, я не уверен, что я действительно ответил на ваш вопрос, поэтому, если вы хотите получить дополнительные разъяснения, пожалуйста, спросите.
В чем разница между 'SizeOf (без знака длинного межд)' и 'SizeOf (длинный межд)'? И 'size_t' фактически' unsigned'. –
Я забыл набрать 'unsigned'. –
Включить предупреждения компилятора и '-Wconversion' (gcc). Это должно дать вам подсказки, где у вас есть потенциальные проблемы с усечением или знаком. Жонглирование с помощью подписанных и беззнаковых целых чисел иногда довольно сложно. – Olaf