Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why ssize_t in Visual Studio 2010 is defined as unsigned?

Tags:

c

types

windows

I have a portable program which uses ssize_t under the assumption it is a signed integer. Conceptually it does something like:

#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");
}

One would expect the program to print 'negative' but instead it prints 'positive'. The reason is easy to see from how ssize_t is defined (in 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

And so, subtracting two unsigned values results in an unsigned value and hence the result.

In older versions of the Windows SDK (e.g. V7.0A) the ssize_t was correctly defined as:

//
// 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;

Can anyone explain this change? Are we supposed to stop using ssize_t on Windows?

Update: Based on all the answers, it appears to be a bug in Visual Studio 2010 which includes ssize_t but defined incorrectly. This is a sneaky and nasty bug.

Last Update: This bug has been fixed in VS2012 and VS2016. Also from the comment discussion it appears that this way of calculating len_diff is problematic when the values compared are of different signs when casted to SSIZE_T

like image 982
Dror Harari Avatar asked Mar 08 '14 05:03

Dror Harari


2 Answers

Would this be a good solution?

#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
like image 124
Scott Wardlaw Avatar answered Oct 13 '22 22:10

Scott Wardlaw


ssize_t is not standard C, it is a typedef from Posix. That you found it in a code analysis header for VS2010 probably has something to do with the origin, most code analysis tooling started on Unix. It is removed again in VS2012 and up.

That it is present in the BaseTsd.h SDK file in all caps certainly is not a mistake, Windows supported a Posix subsystem. These typedefs insulate the operating system from compiler implementation details, the basic reason that Windows managed to survive architecture changes, moving from 16 to 32 to 64-bit.

So the real problem is that you are trying to compile a Posix program on Windows but without using Posix headers. Trivial to solve, just add your own typedef before the #includes.

like image 38
Hans Passant Avatar answered Oct 13 '22 23:10

Hans Passant