我有一个可移植的程序,假设它是有符号整数,它使用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;
任何人都可以解释这个变化吗?我们应该停止在Windows上使用ssize_t吗?
更新的 根据所有答案,它似乎是Visual Studio 2010中的一个错误,其中包含ssize_t但未正确定义。这是一个偷偷摸摸和讨厌的错误。
上次更新: 此错误已在VS2012和VS2016中修复。同样从评论讨论看来,当比较的值在转换为SSIZE_T时具有不同的符号时,这种计算len_diff的方式是有问题的
答案 0 :(得分:13)
这会是一个很好的解决方案吗?
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
答案 1 :(得分:10)
ssize_t
不是标准C,它是来自Posix的typedef。您在VS2010的代码分析头中找到它可能与原点有关,大多数代码分析工具都是在Unix上启动的。它在VS2012及以上版本中再次删除。
它存在于BaseTsd.h SDK文件 in all caps 当然不是错误,Windows支持Posix子系统。这些typedef将操作系统与编译器实现细节隔离开来,这是Windows设法在架构更改后生存的基本原因,从16位移至32位。
所以真正的问题是你试图在Windows上编译Posix程序但不使用Posix头。要解决的问题很简单,只需在#includes之前添加自己的typedef。
答案 2 :(得分:5)
虽然肯定不符合POSIX标准,ssize_t
是无符号整数,但OP的代码也有可能在符合POSIX标准的系统上中断。
作为POSIX defines ssize_t
to (at least) just cover the -1
and nothing else negativ:
<强> ssize_t供强>
用于计算字节数或错误指示。
[...]
ssize_t 类型应至少能够存储[-1,{SSIZE_MAX}]范围内的值。