【问题标题】:How do strings work in C?字符串在 C 中是如何工作的?
【发布时间】:2018-05-05 18:24:48
【问题描述】:

字符串在C编程语言中被称为常量。

所以,当我给出像char *s = "Hello" 这样的语句时,我了解到s 指向H 的内存位置,因为“Hello”存储在程序的某个静态内存中,并且"Hello" 也是不可变的。

这是否意味着变量s 现在是指向常量数据的指针 类型的变量,例如const int a = 3;const int *i = &a;。这似乎是因为我无法操作数据(当我这样做时,会导致分段错误)。

但是,如果是这样,编译器不应该能够检测并说我已将合格数据分配给不合格变量。 char *p p 是指向非限定字符的指针,当我说char *p="Hello" p 时,指向非限定字符的指针不能指向 const 字符类型

我在这里错过了什么?

如果不是上述情况,那么如何使常量字符数组不可变?

【问题讨论】:

  • 您查看过C11 标准文档n1570 的内部吗?您真的应该下载然后阅读该规范。顺便说一句,ansi-c(甚至 C99)都是过时的标准。
  • variable s 不是 const (除非另有说明),您仍然可以使用它来指向其他位置。 "Hello" 存储在程序的 data section 部分中,这就是它不可变的原因。

标签: c string c99 ansi-c


【解决方案1】:

语法 char *s = "Hello"; 是从 const 关键字不是 C 规范的一部分的日子开始出现的。后来它仍然是为了反向兼容。写这样的s[i] 会导致未定义的行为。 (在您的情况下观察到 Seg 故障几次运行)

这种行为(从字符串文字或 const char [] 转换为非常量 char *)在 C++ 中得到了短暂的支持,直到 C++11 才被弃用。

C 中的类型安全是有限的。

【讨论】:

  • “短暂地直到 C++11”?那将是22年左右。你认为什么是长时间? :)
【解决方案2】:

首先,C 中的 string 不是不可变的。 C 甚至不知道字符串的 type —— string 只是定义为以'\0' 结尾的char 序列。

您所说的是字符串文字,它们可以是不可变的。 C 标准定义尝试修改字符串文字是未定义的行为,但它们的类型仍然是char *。因此,如果您确定在您的 C 实现中,字符串文字是可写的,那么您可以这样做! *)

但是您的代码将不再是明确定义的 C 代码,并且无法在具有只读字符串文字的其他平台上运行。它将编译,因为通过char * 编写完全没问题,但在运行时会以不可预知的方式失败(例如,可能是崩溃)。

因此,可移植代码的最佳做法是仅将字符串文字分配给const char * 指针,如果您需要可变字符串,请将字符串文字用作char []初始化程序 .


*) 注意这是非常不常见的,现在你会发现它只有针对嵌入式或非常旧的平台的专门编译器。现代平台将字符串文字放置在只读数据段或类似数据段中。

【讨论】:

  • 即使你确定字符串文字在你的实现中是可变的,改变一个仍然是未定义的行为,所以你不能这样做。同样,您可以确定您的实现不会因算术溢出而陷入困境——事实上,GCC 被记录为没有陷入困境——但编译器仍然会产生令人惊讶的结果。见blog.regehr.org/archives/759
  • 无论您是否相信它是一个“UB 技巧”,事实是编译器可能会不断地将布尔值 x < x + 1 折叠为 1,即使它会评估为 0 x 的特定值,因为在 UB 的情况下它只会评估为 0。类似地,如果编译器知道char* p 的值是指向字符串文字的指针,它可以选择不编译*p = 'a';,它甚至可以选择不编译该基本块中的以下代码,假设程序员一定是做了一些事情来保证不会发生 UB。
  • 你所指的现实有参考吗?也就是说,一个使字符串文字可变的编译器?如果不是,那都是理论上的,不是吗?如果是这样,你怎么知道编译器永远不会获得我所说的那种优化?当 GCC 获得这些优化时,它确实让 Linux 作者和其他人感到惊讶,他们有理由相信他们的平台不会捕获整数溢出。不管怎样,对我来说就是这样。
  • @rici 例如cc65 和命令行选项--writable-strings 为您提供了保证。我仍然编辑了答案,以使关于依赖此类事物的警告更加明显。但实际上,UB 并不意味着“你不能那样做”,它只是意味着“你的代码不是定义明确的 C,所以它很容易崩溃”。
猜你喜欢
  • 2016-12-12
  • 2017-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多