1

在使用 PIC24FJ128GB204 在 MPLAB X 中工作时学习嵌入式 C。

到目前为止,我大多听说应该在嵌入式设备上尽可能多地使用无符号类型(尤其是?),所以我开始使用 uint8_t 数组来保存字符串。但是,如果我从 stdlib.h 调用 itoa,它需要一个指向有符号字符 (int8_t) 数组的指针:

extern char * itoa(char * buf, int val, int base);

当我在无符号数组上使用 itoa 后尝试编译时,这一点特别清楚:

main.c:317:9: warning: pointer targets in passing argument 1 of 'itoa' differ in signedness
c:\program files (x86)\microchip\xc16\v1.36\bin\bin\../..\include/stdlib.h:131:15: note: expected 'char *' but argument is of type 'unsigned char *'

在其他平台上搜索 itoa 的实现,这似乎是常见的情况。

这是为什么?

(我还注意到,大多数实现都需要值/指针/基数,而-出于某种原因-Microchip 的 stdlib.h 首先需要指针。我花了一段时间才意识到这一点。)

4

4 回答 4

6

charassigned或unsigned是几十年前的妥协——当时为当时的编译器带来一定程度的一致性是有道理的

itoa(),虽然不是标准的 C 库函数,但遵循该约定,因为字符串char.

许多库函数使用字符串指针。 itoa()也是如此,并将内部工作作为unsigned char. 请记住,字符串是表示文本,而不是数字 - 所以char本身的签名并不是一个很大的问题。当然,重点itoa()是取一个数字(int)并形成一个字符串

在许多情况下,C 库在char 功能上“好像”对待它。unsigned char

  • int fgetc()返回一个EOF或在unsigned char范围内的值。

  • printf() "%c":“int参数被转换为unsigned char,并写入结果字符。”

  • <string.h>“对于本子条款中的所有功能,每个字符都应被解释为好像它具有类型unsigned char(因此每个可能的对象表示都是有效的并且具有不同的值)。”

  • <ctype.h>“在所有情况下,参数都是 an int,其值应可表示为 anunsigned char或应等于宏的值EOF

于 2020-02-18T15:27:57.913 回答
4

到目前为止,我大多听说您应该在嵌入式设备上尽可能多地使用无符号类型(尤其是?),

你听过这个的人解释过为什么吗?这种解释是基于可靠的分析和工程,还是凭空出现的?

经验法则的问题在于,它们经常在错误的情况下被不假思索地应用。需要使用无符号类型时使用无符号类型,需要使用有符号类型时使用有符号类型。

我已经开始使用 uint8_t 数组来保存字符串。

不。这不是它的目的。

根据环境, Plainchar可能已签名或未签名。基本字符集(大写和小写拉丁字母、十进制数字和基本图形字符集)的字符编码总是非负的,但扩展字符可能具有正编码或负编码。

6.2.5 类型
...
3 声明为类型的对象char大到足以存储基本执行字符集的任何成员。如果基本执行字符集的成员存储在 char对象中,则其值保证为非负数。如果任何其他字符存储在char对象中,则结果值是实现定义的,但应在该类型可以表示的值范围内。

C 2011 在线草案

处理字符串的 C 库函数需要指向char、 notunsigned charuint8_t其他任何东西的指针。虽然对于任何提供它的平台很可能uint8_t只是一个 typedef 名称unsigned char,但这并不是保证。 char必须至少8 位宽,但有些平台可能更宽(其中一个旧 PDP 使用 9 位字节和 36 位字,并且根据应用程序,我可以看到一些使用不稳定的专用嵌入式系统尺寸)。

于 2020-02-18T15:35:27.777 回答
2

到目前为止,我大多听说你应该在嵌入式设备上尽可能多地使用无符号类型(尤其是?)

这主要是因为(意外或有意)带符号的操作数与按位运算符混合会造成严重破坏。但在低级编程中,实际上需要使用有符号类型的情况并不多。

例如,MISRA-C 强制您始终使用无符号变量、操作数和整数常量,除非打算实际使用有符号类型。所以这不仅仅是基于意见的东西,MISRA-C 是大多数专业嵌入式系统的事实上的行业标准。

所以我开始使用 uint8_t 数组来保存字符串

没关系,但char用于此目的也没有错。唯一可以使用的时间是char您打算存储文本时。请注意,这char尤其令人讨厌,因为与语言中的所有其他类型不同,它具有未知的符号。每个编译器都可以生成char有符号或无符号,并且仍然符合 C 标准。因此,依赖于char已签名或未签名的代码被破坏了。但是,对于文本字符串,这无关紧要,因为它们总是积极的。

但是,如果我从 stdlib.h 调用 itoa,它需要一个指向有符号字符 (int8_t) 数组的指针:

您的编译器显然将char其视为已签名。首先请注意,这不是标准 C,当需要严格的 C 标准一致性时itoa,它不允许存在于内部。stdlib.h但更重要的是,不同的编译器可能会以不同的方式实现该功能,因为它不是标准化的。

事实证明,您可以安全地在各种字符类型之间随意转换:char、、、和(即使标准没有明确说明unsigned char,stdint.h 8 位类型几乎肯定是字符类型)。字符类型特别具有与之相关的各种特殊规则,这意味着您始终可以将某些内容转换为字符类型。signed charint8_tuint8_t

只要不存在限定符(等),您就可以安全地将uint8_t数组转换为 a 。char*const

于 2020-02-18T15:52:27.067 回答
1

到目前为止,我大多听说你应该尽可能地使用无符号类型

首先——这根本不是事实——你应该使用正确的类型What is the correct type?它是最适合您需求的类型。How can I know which type is best for me?这取决于你用它做什么。它应该有一个类型来存储您的程序可能想要存储在其中的所有可能值。

所以你不应该再听这个人的。

于 2020-02-18T15:11:31.973 回答