为什么Visual Studio 2010中的ssize_t被定义为unsigned?

Dro*_*ari 13 c windows types

我有一个可移植的程序,它假设它是有符号整数,使用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");
}
Run Code Online (Sandbox Code Playgroud)

人们会期望该程序打印"负面",而是打印"正面".原因很容易从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
Run Code Online (Sandbox Code Playgroud)

因此,减去两个无符号值会导致无符号值,从而得到结果.

在旧版本的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;
Run Code Online (Sandbox Code Playgroud)

谁能解释这个变化?我们应该停止在Windows上使用ssize_t吗?

更新: 根据所有答案,它似乎是Visual Studio 2010中的一个错误,其中包括ssize_t但未正确定义.这是一个偷偷摸摸和讨厌的错误.

最后更新: 此错误已在VS2012和VS2016中修复.同样从评论讨论看来,当比较的值在转换为SSIZE_T时具有不同的符号时,这种计算len_diff的方式是有问题的.

Sco*_*law 17

这会是一个很好的解决方案吗?

#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
Run Code Online (Sandbox Code Playgroud)


Han*_*ant 10

ssize_t标准的C,它是从Posix的一个typedef.您在VS2010的代码分析头中找到它可能与原点有关,大多数代码分析工具都是在Unix上启动的.它在VS2012及以上再次删除.

它存在于所有大写的BaseTsd.h SDK文件当然不是一个错误,Windows支持Posix子系统.这些typedef将操作系统与编译器实现细节隔离开来,这是Windows设法在架构更改后生存的基本原因,从16位移至32位.

所以真正的问题是你试图在Windows上编译Posix程序但不使用Posix头.要解决的问题很简单,只需在#includes之前添加自己的typedef.

  • 汉斯,谢谢,但是typedef出现在sourceannotations.h中,它使用in / out / ...宏注释了所有API,因此默认情况下它仅包含在stdint.h和stdio.h中-所讨论的“ posix”代码是LMDB (http://symas.com/mdb/),它是众多“便携式”库之一。仍然没有意义的原因是,如果他们费心定义ssize_t,就会以错误的方式显式定义它(如正确定义的all-caps版本所示)。 (2认同)

alk*_*alk 6

尽管肯定不是ssize_t一个无符号整数不符合POSIX标准,但是OP的代码也有可能在符合POSIX标准的系统上中断。

正如POSIX所定义ssize_t的(至少)仅涉及-1和否定否定法

ssize_t

用于字节计数或错误指示。

[...]

ssize_t类型应能够存储至少在[-1,{SSIZE_MAX}]范围内的值。