为啥处理字节的 Windows API 调用(例如“recv”)使用默认签名的 char*?

Posted

技术标签:

【中文标题】为啥处理字节的 Windows API 调用(例如“recv”)使用默认签名的 char*?【英文标题】:Why do windows API calls dealing with bytes (such as 'recv') use char*, which is signed by default?为什么处理字节的 Windows API 调用(例如“recv”)使用默认签名的 char*? 【发布时间】:2016-04-16 12:01:48 【问题描述】:

我对 c/c++ 还很陌生,我正在尝试遵循一些建议,建议尽可能使用 stdint.h 定义的类型(uint8_t 等而不是 unsigned char)。

但是,当您调用需要 char* 缓冲区(例如 recv)的 API 时,您似乎必须使用 API 规定的任何类型。

我不明白的是,如果你正在读取字节,为什么你不希望它是无符号的,所以你得到的值在 0 到 255 之间而不是 -128 和 127 之间。

我不知道这是否是特定于实现的,但我只见过char 默认为已签名。

您是否希望将此类调用的结果转换为 unsigned char*uint8_t* 以允许您解释更高的正值?

【问题讨论】:

因为调用只需要一个指针,我认为最初的设计者认为这两种方式都无关紧要。 首先要学习的是没有语言C/C++,只有两种不同的语言C和C++。也就是说,C 标准没有为char 定义特定的签名,所以这是一个窗口问题。而且 WinAPI 远没有使用现代 C 编程风格; stdint.h 在设计时没有用。对于这些功能,char 是签名还是未签名可能都无关紧要。 @Olaf 啊,好的。那么它是特定于实现的吗?我只需要解释它,但对我所写的内容有意义吗? @Twicetimes:这是 C bascis,您会在每本优秀的 C 书籍中找到答案,当然还有标准。甚至不清楚您使用char 的问题是什么。如果你不做算术,几乎没有区别。 【参考方案1】:

在 Windows 上,recv 是 Winsock API 的一部分,它起源于 4.2BSD 套接字 API 的克隆。 4.2BSD 早于 ANSI C 和 void 关键字,因此它使用 char *,因为它是当时最接近通用指针的东西。

后来,void被发明后,BSD等Unix系统更新了recv的定义,现在都使用void *。这种改变的动机很明确:char * 并不是一个真正的通用指针,使用它会使你的代码更丑陋,并且有更多的强制转换。 void * 版本的recv 也是 POSIX 强制要求的,因此唯一没有它的操作系统供应商是最不关心 POSIX 合规性和代码美学的供应商......微软。

【讨论】:

那么在符合 POSIX 标准的版本上,您总是需要强制转换它? 不,void * 你永远不需要演员表。你可以传递任何类型的指针。 好的,但是在解释结果时,大概我需要转换为 uint8_t 或类似的,否则当我尝试读取字节值时,我会得到 -128 而不是 128,例如? 感谢历史背景顺便说一句。总是有助于理解为什么事情会变成现在这样。 我不知道你为什么认为你需要一个“解释”演员。如果你想接收uint8_t的流,你可以创建一个像uint8_t a[1000];这样的数组,然后像recv(s, a, sizeof a)这样直接将它传递给recv,然后(在对返回值进行适当的错误检查之后)继续使用a[0], a[1], ... 不需要演员表。如果你的recv 需要char *,那么你只需要一个演员recv(s, (char *)a, sizeof a)

以上是关于为啥处理字节的 Windows API 调用(例如“recv”)使用默认签名的 char*?的主要内容,如果未能解决你的问题,请参考以下文章

golang 调用windows API 中文的处理

为啥易语言用windows api没有效果

Java应用程序为啥既可在windows中运行也可在Linux中运行

为啥在windows上调用多处理模块的函数时python可执行文件会打开新的窗口实例

为啥我不应该使用 catch() 来处理 React useEffect API 调用中的错误?

图形 API 调用返回 GraphMethodException - 为啥?