【问题标题】:Simple question about declaring an empty string in C关于在 C 中声明一个空字符串的简单问题
【发布时间】:2020-04-26 19:27:25
【问题描述】:

当我通过以下方式声明字符串时,没有收到任何编译器警告:

static uint8_t test[3] = {'0','0','0'};   // (1)
static uint8_t test[3] = "";              // (2)
uint8_t test[3] = "";                     // (3)

(2)和(3)有什么区别。这是可以做还是不好的编程习惯?

还有字符串是如何存储在内存中的?

我们有没有可能写超出 3 的大小?

当我这样做时:

uint8_t test[3] = ""; // 



test[0] = 0  test[1] = 0  test[2] = 0  test[3] = /0 (null character indicating the end of the string)

或者做

uint8_t test[3] = "123";



test[0] = ‘1’ 
test[1] = ‘2’ 
test[2] = ‘3’ 
test[3] = /0 (null character indicating the end of the string)

空终止符存储在哪里?

和有什么区别

test[3] = ""
test[3] = '\0'

对我来说,这似乎是我将所有位置归零,但也将位置 3 作为起始地址归零,这就是我感到困惑的原因。

uint8_t test[3] = ""
uint8_t test[3] = '\0'

【问题讨论】:

  • 请注意 1. 和 2. 不一样。在 2. 你得到一个 '\0' 的数组,而在 1. 你得到一个 '0' 的数组。所以 1. 不是一个正确的以 null 结尾的字符串。
  • 数字 1 和 2 具有静态 storage duration 和可能内部 linkage。 3 号没有。
  • 严格来说,这些根本不是字符串。使用uint8_t 表示这些是 numerical 值的数组,它们恰好是根据字符/字符串文字初始化的......
  • @Blaze 你确定 2. 生成 3 个连续的 \0 吗?
  • @linuxfansaysReinstateMonica 是的,参见here“所有未显式初始化的数组元素都以与具有静态存储持续时间的对象相同的方式隐式初始化。” 和@ 987654324@:“具有静态和线程本地存储持续时间的对象初始化如下[...]整数类型的对象被初始化为无符号零”

标签: c string types embedded


【解决方案1】:

当我通过以下方式声明字符串时,没有收到任何编译器警告

您不应该这样做,因为uint8_t 极有可能对应于unsigned char

(支持uint8_t但不将其解析为字符类型的虚构的理论编译器会被破坏,无用的实现。)

(2)和(3)有什么区别

可能是链接和存储时间。取决于声明变量的位置。这与uint8_t 或字符串本身无关。

这是可以做还是不好的编程习惯?

可以将uint8_t 用于字符串,但在通用C 编程案例中有点奇怪。

有一些特殊情况,例如某些类型的嵌入式系统,希望确保字符始终为无符号类型,因为它们会生成显示符号表或基于字符串的协议等。在此类系统上,总是使用uint8_t 或 @ 987654328@,永远不要char

还有字符串是如何存储在内存中的?

为 3 个字节,初始化为零值 (0x00)。不要与字符符号零混淆'0' (0x30)。

在哪里 再次存储它取决于它在哪个作用域中声明。请注意,字符串文字本身存储在与读/写数组不同的内存中。行业事实上的标准类似于this example

我们有没有可能写超出 3 的大小?

是的,如果你做test[3] = '\0'; 之类的蠢事。声明为大小为 3 的数组只能访问元素 0、1 和 2,因为数组索引在 C 中是零索引的。

test[3] = '\0' ...空终止符存储在哪里?

没有人知道,这是未定义的行为。它不能保证存储在任何地方,您的程序可能会崩溃。或者你碰巧运气不好,你的系统允许你写入那个内存位置。

test[3] = ""test[3] = '\0' 有什么区别

前者是语法错误,后者写入超出数组范围。两者都不正确。

这就是我困惑的原因

您对数组声明与数组访问感到困惑。他们看起来一样,但做的事情不同。 uint8_t test[3] = ""; 只能在声明/初始化期间使用。声明期间的[3] 表示大小为3 的数组。但数组访问期间的[3] 表示访问仅包含[0][1][2] 项的零索引数组中的项3。

"" 初始值设定项等价于 {'\0'},空终止。然后在 C 中有一条规则指出,如果一个数组被部分初始化,所有未显式初始化的元素都将被隐式初始化为零值。在"" 的情况下,第一项显式初始化为零,因为它是一个空终止符,其余项被隐式初始化为零,因为数组就是这样工作的。

【讨论】:

  • 我很确定如果uint8_t 存在,它必须unsigned char 相同。 char 类型不能更小,如果更大,则不能有uint8_t(我们不能有任何小于char 的可寻址对象)。
  • @TobySpeight 是的。我的评论主要是关于指针别名,其中uint8_t 在理论上并没有明确地与标准中任何地方的字符类型进行别名。但是,如果没有,编译器将是无用的废话。所以这是一个实施质量问题,即使不将其映射到字符类型会很疯狂。
  • 啊,有道理;我想知道为什么它“极有可能”而不是保证。感谢您的解释。
  • @TobySpeight 我想还有一个奇异的 1 的补码或有符号幅度系统的高度理论场景,其中 char 具有系统的奇怪符号格式,而 int8_t 由标准保证为2 的补码。那么就有正当理由保持类型不兼容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-08
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多