【问题标题】:How does "str" - "str" in C work? How are they stored?C中的“str”-“str”如何工作?它们是如何存储的?
【发布时间】:2017-11-18 08:15:07
【问题描述】:

免责声明:此问题询问 "str literal" + "str literal" 的工作原理

'a' + 'b''9' - '0' = 9 ('character' + 'character') 的工作原理:


问题:

对C语言比较熟悉的各位,感谢阅读

(用clang编译,标准=C11)

示例:

(尝试在没有".c" 扩展名的情况下打印__FILE__

printf("%s\n", __FILE__); 返回filename.c

printf("%.*s\n", (int)(".c" - __FILE__), __FILE__); 返回 filename

1. C如何将字符串/字符串文字类型转换为int?是否忽略空格?

  • (int)"string" 的值代表什么?

另一个例子:

(int)("word" - "rd") = 6273
(int)("rd" - "word") = -6273
(int)("word" - "  rd") = -5
(int)("  rd" - "word") = -5

为什么(int)(".c" - __FILE__) 甚至可以工作?

3. 上面的printf 函数真的有效吗?

4. 有没有等价于 'a' + 1 = 'b' 的字符串?

提前谢谢各位!



无关猜测:

1 为什么(int)(".c" - __FILE__) 甚至可以工作?

猜测

  some value of (first?) pointer to ".c" 
- some value of (first?) pointer to __FILE__ string literal 

2.(int)"string"的值究竟代表什么?

  • 为什么(int)(".c" - __FILE__) 甚至可以工作?

idk 但这是另一个例子:

printf("%i", (int)".c");
printf("%i", (int)__FILE__);
printf("%i", (int)(".c" - __FILE__));
printf("%i", (int)(__FILE__ - ".c"));
printf("%./*i", (int)(".c" - __FILE__), (int)__FILE__);
printf("%./*i", (int)(".c" - __FILE__), (int)("c" - __FILE__));

output
---------------------
(int) ".c"= 4357629
(int) __FILE__= 4357620
(int) (".c" - __FILE__) : 9
(int) (__FILE__ - ".c"): -9
(int with precision specified) __FILE__ : 004357620
(int with precision specified) (".c" - __FILE__): 000000009 
$

3.printf 真的有效吗?

假设确实如此,可能:

printf("%.*s",(int)(".c" - __FILE__), __FILE__)
    width = (int)(".c" - __FILE__)   
    specifier/str = __FILE__

printf__FILE__ 打印为宽度为(".c" - __FILE__) 的字符串(少两个字符)

【问题讨论】:

  • 字符串是一个字符数组。在大多数情况下,当数组用作左值时,它会转换为指向第一个元素的指针。将指针转换为int 是实现定义的,但通常它只是将指针的地址作为整数返回。
  • 哦,所以(int)"string"(base 10) &(str[0]) 说的一样?
  • 到处都是未定义的行为。甚至没有为不在同一个数组中的对象定义指针算法。实际上,运行时可能会因违反范围检查而中止
  • 另外,在问题中,您说问题是关于“"str" + "str" 的工作原理”——不,不是,"str" + "str" 根本不起作用(试一试)。跨度>

标签: c string character string-literals integer-arithmetic


【解决方案1】:

您的示例中发生了三件事。

首先,C 中的指针算术规则是两个指针可以相减以产生两个指针之间的 地址 差异。比如:

char test[2] ;
char* t1 = &test[0] ;
char* t2 = &test[1] ;
ptrdiff_t d = t2 - t1  ; // d == 1

ptrdiff_t 是一个整数类型,能够保存 any 两个指针之间的差异。转换为 int 可能是错误的,对于 32 位 int 它将仅跨越 2Gb - 因此该错误不太可能发生。

发生的第二件事是,在表达式中使用诸如"word" 之类的字符串文字是指向字符串内容的指针

发生的第三件事是您的链接器执行了重复字符串消除。它已经详尽地搜索了您的代码以查找相同的字符串文字,并用单个指针替换它们。您的这部分观察取决于实现,可能不适用于所有工具链,甚至是具有不同编译器/链接器设置的相同工具链。

内置宏__FILE__ 是一个字符串文字,其中包含实例化它的源文件的名称。在示例中:

(int)(".c" - __FILE__)

__FILE__ == "filename.c" 并且链接器在其中找到重复的".c"(它必须在末尾,因为 nul 终止符必须匹配)。所以两个指针值的差是8("filename"的长度)。所以声明:

printf("%.*s\n", (int)(".c" - __FILE__), __FILE__);

打印字符串"filename.c" 的前8 个字符,即"filename"

发生了一些更复杂的事情:

(int)("word" - "rd") = 6273
(int)("rd" - "word") = -6273
(int)("word" - "  rd") = -5
(int)("  rd" - "word") = -5 

在第一种和第二种情况下,您可能从第一个 __FILE__ 示例中分别期望 -2 和 2,但是可能会出现这种情况,除非在这种情况下,链接器可能已将 "rd" 与 @ 的结尾匹配987654338@ 字符串而不是"word" 的结尾。链接器行为是实现定义的和非确定性的。结果可能会有所不同,例如,如果您删除了第三个和第四个表达式以使字符串文字不再存在。可以引用来自完全不同的链接模块的字符串。

关键是您不能依赖这种完全未定义/实现的行为(字符串消除即 - 指针算法和文字字符串指针行为已明确定义)。作为对链接器行为的检查很有趣,但作为一种编程技术没有用。

【讨论】:

  • "字符串文字 ... 是指向字符串内容的指针" 我知道您可能知道,但这过于简化了。所以不,字符串是数组。数组不是指针。
  • @Clifford 1. ...two ptrs may be subtracted to yield the difference in address btwn the two ptrs. Thaaank 你。 2. ..._duplicate string elimination_...replaced them with a single ptr... and is implementation dependent+ (it must be at the end because the nul terminator must match) 感谢您提供这些位。想知道这个 dup 字符串消除 是否是优化功能的一个示例? 3.It is not useful as a programming technique.同意。就像你说的,不切实际但仍然很有趣。感谢您揭秘!
  • @alk :表达式求值中使用的值是一个指针。数组不是 C 中的一等类型,不能在表达式中使用 - 它们降级为用于评估的指针。我想我的答案很清楚,没有涉及不必要的细节。
  • @cdpp : 是的,字符串消除是链接器优化。在大多数工具链中,它可以通过链接器命令开关来控制。
【解决方案2】:

一个字符串(带双引号),例如"abc",在用作表达式时转换为指针。如果将整数添加到指针,则会得到一个新指针。如果你减去两个兼容的指针,你会得到一个整数。

一个字符(带单引号),例如'x',只是一个整数。您可以像任何其他整数一样添加、减去它们等。

__FILE__ 扩展为一个字符串,因此".c" - __FILE__ 是两个指针相减得到的整数。

如果将指针转换为整数,则会得到一个整数。

请记住,一些涉及指针的表达式可能没有明确定义,但数据类型是。

【讨论】:

  • 感谢您的快速回复!真的很喜欢你的答案是多么简单
  • 澄清一下,new pointer = integer + pointer 基本上就是type* b = type* a[0 + i] ?
  • 简洁但没有解释为什么printf("%.*s\n", (int)(".c" - __FILE__), __FILE__);会打印"filename"
  • "字符串 ... 只是指针" 不,不,不。它们是数组。数组不是指针!
  • @alk 你误引我了。确切的引用是“字符串......只是指针在表达式中使用时”而且,是的,数组名称也只是指针在表达式中使用时
猜你喜欢
  • 2015-07-18
  • 1970-01-01
  • 2021-10-27
  • 2022-01-05
  • 2015-06-18
  • 1970-01-01
  • 2020-01-19
  • 1970-01-01
  • 2012-02-14
相关资源
最近更新 更多