【问题标题】:Legal to initialize uint8_t array with string literal? [duplicate]用字符串文字初始化 uint8_t 数组是否合法? [复制]
【发布时间】:2021-08-26 05:44:12
【问题描述】:

可以从字符串文字初始化uint8_t 数组吗?它是按预期工作还是由于有符号-无符号转换而破坏了一些字节? (我希望它只是将文字的位原封不动地塞进去。)GCC 不会抱怨 -Wall 并且它似乎有效。

const uint8_t hello[] = "Hello World"

我正在使用一个将字符串作为uint8_t * 的API。现在我正在使用演员表,否则我会收到警告:

const char* hello = "Hello World\n"
HAL_UART_Transmit(uart, (uint8_t *)hello, 12, 50);
// HAL_UART_Transmit(uart, hello, 12, 50);
// would give a warning such as:
// pointer targets in passing argument 2 of 'HAL_UART_Transmit' differ in signedness [-Wpointer-sign]

在这个平台上,char 是 8 位且有符号的。在这种情况下可以使用uint8_t 而不是char 吗?请不要关注 constness 问题,API 应该采用 const uint8_t * 但没有。这个 API 调用只是让我想到这个问题的例子。


令人讨厌的是,这个问题现在已经结束,我想自己回答。抱歉在此处添加此信息,我无权重新打开。

以下所有内容都适用于gcc -Wall -pedantic,但第四个警告关于将有符号转换为无符号。 内存中的位模式将是相同的,如果您将这样的对象转换为(uint8_t *),它将具有相同的行为。根据marked duplicate,这是因为您可以将字符串文字分配给任何 char 数组。

const char string1[] = "Hello";
const uint8_t string2[] = "Hello";
uint8_t string3[] = "Hello";
uint8_t* string4 = "Hello";
char* string5 = "Hello";

当然,只推荐前两个,因为您不应该尝试修改字符串文字。在上面的具体案例中,您可以创建一个包装函数/宏,或者只是将强制转换保留在内部作为对 API 的让步,然后就这样结束了。

【问题讨论】:

  • 如果您很确定 char 是 8 位,则不应该。
  • 显示函数定义,而不是描述你认为它是什么。也显示确切的警告,而不是“警告”。
  • 我更关心将指向非可变数据的指针传递给期望指向可变数据的指针的函数,并将其从警告图表中剔除。如果HAL_UART_Transmit 不打算修改数据,则强制转换为非常量。
  • 我添加了警告,尽管它确实与问题无关(即:我可以将字符串文字分配给uint8_t *unsigned char * 数组,而不是将其分配给char *稍后再进行转换。我试图调用的函数让我想到这个是HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
  • @WhozCraig 我同意,但 API 就是这样(使用非常量,但合同是它不会修改数据)。有很多地方你必须对 API 设计中的问题进行有趣的转换。我正试图让我的代码更理智一点。

标签: c stdint


【解决方案1】:

C 2018 6.7.9 14 告诉我们“字符类型的数组可以由字符串文字或 UTF-8 字符串文字初始化……”

C 2018 6.2.5 15 告诉我们“charsigned charunsigned char 三种类型统称为字符类型。”

C 2018 6.2.5 4 和 6.2.5 6 表示可能有扩展整数类型

没有声明任何扩展整数类型都是字符类型。

C 2018 7.20 4 告诉我们“对于此处描述的实现提供的每种类型,<stdint.h> 应声明 typedef 名称......”和 7.20.1 5 告诉我们“当 typedef 名称仅在不存在或存在定义了初始u,它们应表示相应的有符号和无符号类型,如6.2.5中所述......”

因此,C 实现可以提供无符号 8 位类型,它是扩展整数类型,而不是 unsigned char,并且可以将 uint8_t 定义为这种类型,然后 6.7.9 14 并没有告诉我们这种类型的数组可以由字符串字面量初始化。

如果实现允许您使用字符串字面量初始化 uint8_t 数组,则要么将 uint8_t 定义为无符号 charunsigned char,要么将 uint8_t 定义为是扩展的整数类型,但允许您将数组初始化为 C 标准的扩展。由 C 实现来定义该扩展的行为,但我希望它能够像初始化字符类型数组一样工作。

(可以想象,将uint8_t 定义为扩展整数类型并禁止将其视为字符类型,这对于区分允许为任何对象起别名的字符类型与纯整数类型(不允许这样的别名。这可能允许编译器执行额外的优化,因为它会知道别名不会发生,或者可能诊断某些错误。)

字符串文字的元素具有类型 char(由 C 2018 5.2.1 6)。 C 2018 6.7.9 14 告诉我们“字符串文字的连续字节......初始化数组的元素。”每个字节都应该以通常的方式初始化一个数组元素,包括根据 C 2018 6.7.9 11 转换为目标类型。对于您显示的字符串,"Hello World",字符值都是非负的,所以没有问题将他们的char 值转换为uint8_t。如果字符串中有负数字符,它们应该以通常的方式转换为uint8_t

(如果您的八进制或十六进制转义序列的值未在 char 中表示,则初始化中可能存在一些语言律师的怪异。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    • 2021-03-09
    • 1970-01-01
    • 2011-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多