У меня есть переносная программа, которая использует ssize_t в предположении, что это целое число со знаком. Концептуально он делает что-то вроде:
#include <stdint.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
size_t size_10 = 10;
size_t size_20 = 20;
ssize_t len_diff;
len_diff = (ssize_t)size_10 - (ssize_t)size_20;
if (len_diff < 0)
printf("negative\n");
else if (len_diff > 0)
printf("positive\n");
else
printf("zero\n");
}
Можно ожидать, что программа напечатает "негатив", но вместо этого напечатает "положительный". Причина легко понять из определения ssize_t (в sourceannotations.h):
#ifndef _SSIZE_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 ssize_t;
#else
typedef _W64 unsigned int ssize_t;
#endif
#define _SSIZE_T_DEFINED
#endif
Итак, вычитание двух значений без знака приводит к значению без знака и, следовательно, к результату.
В старых версиях Windows SDK (например, V7.0A) ssize_t был правильно определен как:
//
// SIZE_T used for counts or ranges which need to span the range of
// of a pointer. SSIZE_T is the signed variation.
//
typedef ULONG_PTR SIZE_T, *PSIZE_T;
typedef LONG_PTR SSIZE_T, *PSSIZE_T;
Может ли кто-нибудь объяснить это изменение? Должны ли мы прекратить использование ssize_t в Windows?
Обновление: Основываясь на всех ответах, это, по-видимому, ошибка в Visual Studio 2010, которая включает ssize_t, но неверно определенную. Это непроницаемая и неприятная ошибка.
Последнее обновление: Эта ошибка была исправлена в VS2012 и VS2016. Также из обсуждения комментариев кажется, что этот способ вычисления len_diff проблематичен, когда сравниваемые значения имеют разные знаки при передаче на SSIZE_T