C语言 为什么 Visual Studio 2010 中的 ssize_t 被定义为无符号?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22265610/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 10:51:28  来源:igfitidea点击:

Why ssize_t in Visual Studio 2010 is defined as unsigned?

cwindowstypes

提问by Dror Harari

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

我有一个便携式程序,它使用 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");
}

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):

人们会期望程序打印“负”,但它会打印“正”。从 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

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:

在旧版本的 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;

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

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

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.

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

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

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

采纳答案by Hans Passant

ssize_tis notstandard 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.

ssize_t标准的C,它是从Posix的一个typedef。你在 VS2010 的代码分析头文件中发现它可能与起源有关,大多数代码分析工具都是在 Unix 上开始的。它在 VS2012 及更高版本中再次被删除。

That it is present in the BaseTsd.h SDK file in all capscertainly 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.

以全大写形式出现在 BaseTsd.h SDK 文件当然不是错误,Windows 支持 Posix 子系统。这些 typedef 将操作系统与编译器实现细节隔离开来,这是 Windows 设法在架构变化中幸存下来的基本原因,从 16 位到 32 位再到 64 位。

So the realproblem 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.

所以真正的问题是你试图在 Windows 上编译 Posix 程序,但没有使用 Posix 头文件。解决起来很简单,只需在#includes 之前添加您自己的typedef。

回答by Scott Wardlaw

Would this be a good solution?

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

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

回答by alk

Although it's definitely not conforming the POSIX standard to have ssize_tbeing an unsigned integer, the OP's code risks to also break on systems conforming the POSIX standard.

尽管ssize_t作为无符号整数绝对不符合 POSIX 标准,但 OP 的代码也有在符合 POSIX 标准的系统上中断的风险。

As POSIX defines ssize_tto (at least) just cover the -1and nothing else negativ:

正如POSIX 定义的那样ssize_t(至少)只覆盖 the-1而没有其他否定

ssize_t

Used for a count of bytes or an error indication.

[...]

The type ssize_tshall be capable of storing values at least in the range [-1, {SSIZE_MAX}].

ssize_t

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

[...]

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