Почему ssize t в Visual Studio 2010 определяется как unsigned?

у меня есть портативная программа, которая использует 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("negativen");
    else if (len_diff > 0)
        printf("positiven");
    else
        printf("zeron");
}

можно было бы ожидать, что программа напечатает "отрицательный", но вместо этого она печатает "положительный". Причина легко понять из того, как определяется 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

3 ответов


ssize_t is не стандартный C, это typedef от Posix. То, что вы нашли его в заголовке анализа кода для VS2010, вероятно, имеет какое-то отношение к origin, большинству инструментов анализа кода, запущенных в Unix. Он снова удаляется в VS2012 и выше.

что он присутствует в BaseTsd.H SDK файл во всех шапок конечно, это не ошибка, Windows поддерживает подсистему Posix. Эти typedefs изолируют операционную систему от реализации компилятора подробности, основная причина того, что Windows удалось пережить изменения архитектуры, перейдя от 16 до 32 до 64-бит.

Так реальные проблема в том, что вы пытаетесь скомпилировать программу Posix в Windows, но без использования заголовков Posix. Тривиально решить, просто добавьте свой собственный typedef перед #includes.


будет ли это хорошим решением?

#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif

хотя это определенно не соответствует стандарту POSIX, чтобы иметь ssize_t будучи целым числом без знака, код OP рискует также сломаться на системах, соответствующих стандарту POSIX.

Как POSIX определяет ssize_t чтобы просто покрыть -1 и больше ничего негативного:

определены

используется для подсчета байтов или индикации ошибки.

[...]

тип определены должен быть способен хранить значения по крайней мере в диапазоне [-1, {SSIZE_MAX}].