【问题标题】:int8_t and char: converts between pointers to integer types with different sign - but it doesn'tint8_t 和 char:在指向具有不同符号的整数类型的指针之间转换 - 但它没有
【发布时间】:2014-06-03 10:34:32
【问题描述】:

我正在使用一些嵌入式代码并且我正在从头开始编写一些新的东西,所以我更喜欢坚持使用 uint8_t、int8_t 等类型。

但是,当移植一个函数时:

void functionName(char *data)

到:

void functionName(int8_t *data)

将文字字符串传递给函数时,我收到编译器警告“在指向具有不同符号的整数类型的指针之间转换”。 (即当调用functionName("put this text in"); 时)。

现在,我明白为什么会发生这种情况,这些行只是调试,但我想知道人们认为最合适的处理方式是什么,而不是对每个文字字符串进行类型转换。在实践中,我不觉得笼统的类型转换比使用像“char”这样潜在的模棱两可的类型更安全。

【问题讨论】:

  • 如果你想停止使用char 那你为什么要写字符串文字?我认为试图假装char 不存在是毫无意义的。你需要正视它。
  • 数据的用途是什么?如果是文本,使用char,如果是数字数据,使用u/int8_t
  • 感谢 cmets,字符串文字是调试输出,例如“达到某个点”这些定义确实不同,这里它们是 typedef 的(在我看来正确为:typedef signed char int8_t ; typedef unsigned char uint8_t; 顺便说一句,使用“signed char”而不是“char”也会产生相同的编译器警告。
  • @user694733 如果是字符数据,使用char;如果是数字数据,请使用signed char,如果是原始内存(或位掩码等),请使用unsigned char。只有极少数情况下,如果有的话,int8_tuint8_t 是合适的。 (对于初学者来说,并非所有系统都支持它们。)
  • @JamesKanze - 您的 cmets 对于在每个系统都有一些 x86 兼容处理器的操作系统上运行的软件有效。然而,嵌入式处理器之间代码的可移植性(想想我们在过去五年中都从 8 位 PIC 迁移到 32 位 ARM)。在这种情况下,您已经准确定义了每次声明需要多少位,您可以通过简单地使用适当的 stdint.h 文件来维护它。

标签: c++ c char embedded


【解决方案1】:

你好像做错了,在这里。

C 并未将字符定义为 8 位整数,那么除非您使用 UTF-8,否则为什么您会选择使用 int8_tuint8_t 来表示字符数据?

对于 C 的字符串字面量,它们的类型是指向 char 的指针,而且根本不保证是 8 位的。

如果它是signedunsigned,也没有定义,所以只需将const char * 用于字符串文字。

【讨论】:

  • 我已经看到char 也被用于 UTF-8。只要源文件编码为 UTF-8,就可以使用常规 C 文字。
  • 在嵌入式系统上,您必须自己发明令牌表(例如,在编写在图形 LCD 上键入文本的程序时),通常对字符串使用 uint8_t 是有意义的。这是因为uint8_t 是一个健全且定义明确的类型,它是 100% 可移植的。 char 然而,是一个相当疯狂的类型:它可以是任何大小和任何符号,因此是完全不可移植的。在需要确定性程序行为的地方,您应该使用 stdint.h,无论是用于字符串处理还是整数。
  • @Lundin 那么(对我来说)使用char 仍然更有意义,然后研究编译器为您提供了对目标编码的控制程度。无论如何,您都将依赖编码,因此使其明确和受控是有意义的。
  • @unwind - 您的帖子非常正确,这也是它永远不会起作用的原因。但是 Lundin 关于嵌入式系统的 cmets 是它让我们感到痛苦的原因!我希望有一个优雅的解决方案,但似乎没有。
  • 如果意图表示一个字符,则应该使用char(Unicode 和宽字符除外),如果意图表示一个“小整数”例如,您可以执行算术运算,或映射到硬件寄存器宽度,那么 stdint.h 类型是有意义的。例如,TMS320C55xx 没有 8 位可寻址存储器,并且 char 必须是 16 位。有时这会咬人。大多数编译器允许您使用命令行开关指定 char 是有符号还是无符号 - 也许这就是这里的解决方案。
【解决方案2】:

回答您的附录(@unwind 很好地回答了原始问题)。我认为这主要取决于上下文。如果您正在处理文本,即字符串文字,您必须使用 const char*char*,因为编译器会相应地转换字符。如果没有编写自己的字符串实现,您可能会被编译器提供给您的任何东西所困扰。但是,当您必须与 CPU 上下文之外的某人/某物进行交互时,例如网络,串行等,您必须控制确切的大小(我想这是您的问题的来源)。在这种情况下,我建议编写函数来将字符串或任何数据类型转换为uint8_t 缓冲区以进行序列化发送(或接收)。

const char* my_string = "foo bar!";
uint8_t buffer* = string2sendbuffer(my_string);
my_send(buffer, destination);

string2buffer 函数将了解有关将字符放入缓冲区的所有信息。例如,它可能知道您必须使用 big-endian 字节排序将每个 char 编码为两个缓冲区元素。这个函数肯定是平台相关的,但封装了所有这些平台相关性,因此您将获得很大的灵活性。 其他所有复杂数据类型也是如此。对于其他一切(编译器没有那么强烈的意见),我建议使用stdint.h 提供的(u)intX_t 类型(应该是可移植的)。

【讨论】:

  • 是的,你是对的。在阅读了这里的帖子并看到我没有做错任何事情之后,我将接受类型转换以删除编译器警告(嘿,至少它只是在这些系统的调试中)。我认为让这两种类型保持独立是完全正确的。感谢您的所有 cmets。
  • @AndrewN 您的编译器可能有一个命令行开关来确定 char 是有符号还是无符号 - 这可能是一个更简洁的解决方案。
【解决方案3】:

char 类型是有符号还是无符号由实现定义。看起来您正在使用未签名的环境。

因此,无论何时处理字符,您都可以使用uint8_t 或坚持使用char

【讨论】:

  • 同意,但编译器不喜欢这样。在嵌入式系统上,“char”实际上并不存在。奇怪的是,它是默认签名的(我本来希望是另一种方式)。由于所有这些都喷出的UART对字符无动于衷-它只是按照指示输出8位。因此,不可能将这两种情况分开,但类型检查对于系统的其余部分很重要。
猜你喜欢
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-09
相关资源
最近更新 更多