"str" - "str" 在 C 中如何工作?它们是如何储存的?
How does "str" - "str" in C work? How are they stored?
免责声明:此问题询问 "str literal" + "str literal"
如何工作
关于 'a' + 'b'
或 '9' - '0' = 9
('character' + 'character') 的工作原理:
Why does subtracting '0' in C result in the number that the char is representing?
C character values arithmetic
问题:
致所有更熟悉 C 语言的人,感谢阅读
(用 clang 编译,标准=C11)
Example:
(trying to print __FILE__
without its ".c"
extension)
printf("%s\n", __FILE__);
returns filename.c
printf("%.*s\n", (int)(".c" - __FILE__), __FILE__);
returns
filename
1. How does C typecast string/string literals to int? Are whitespaces ignored?
- What does the value of an
(int)"string"
represent?
Another example:
(int)("word" - "rd") = 6273
(int)("rd" - "word") = -6273
(int)("word" - " rd") = -5
(int)(" rd" - "word") = -5
Why does (int)(".c" - __FILE__)
even work?
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__)
还有效?
同上,但这是另一个例子:
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__)
的字符串(少两个字符)
一个字符串(带双引号),例如"abc"
,在用作表达式 时被转换为指针。如果你给一个指针加上一个整数,你会得到一个新的指针。如果你减去两个兼容的指针,你会得到一个整数。
一个字符(带单引号),例如'x'
,只是一个整数。您可以像任何其他整数一样添加、减去它们等。
__FILE__
扩展为字符串,因此 ".c" - __FILE__
是两个指针相减所得的整数。
如果您将指针转换为一个整数,您将得到一个整数。
请记住,一些涉及指针的表达式可能没有明确定义,但数据类型是。
您的示例中发生了三件事。
首先在 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"
的字符串文字是指向字符串内容的 指针 。
发生的第三件事是您的linker 执行了重复字符串消除。它已详尽地搜索您的代码以查找相同的字符串文字,并用单个指针替换它们。您观察的这一部分取决于实现,可能不适用于所有工具链,甚至可能不适用于具有不同 compiler/linker 设置的同一工具链。
内置宏__FILE__
是一个字符串文字,包含实例化它的源文件的名称。在示例中:
(int)(".c" - __FILE__)
__FILE__
== "filename.c"
并且 linker 在其中找到重复的 ".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,但是除了在这种情况下 linker 可能与"rd"
与 " rd"
字符串的结尾而不是 "word"
的结尾。 linker 行为是实现定义的并且是不确定的。结果可能会有所不同,例如,如果您删除了第三个和第四个表达式以使字符串文字不再存在。可能会引用来自完全不同 link 模块的字符串。
重点是您不能完全依赖此 undefined/implementation 行为(字符串消除即指针算术和文字字符串指针行为已明确定义)。作为对 linker 行为的检查很有趣,但作为编程技术没有用。
免责声明:此问题询问 "str literal" + "str literal"
如何工作
关于 'a' + 'b'
或 '9' - '0' = 9
('character' + 'character') 的工作原理:
Why does subtracting '0' in C result in the number that the char is representing?
C character values arithmetic
问题:
致所有更熟悉 C 语言的人,感谢阅读
(用 clang 编译,标准=C11)
Example:
(trying to print
__FILE__
without its".c"
extension)
printf("%s\n", __FILE__);
returnsfilename.c
printf("%.*s\n", (int)(".c" - __FILE__), __FILE__);
returnsfilename
1. How does C typecast string/string literals to int? Are whitespaces ignored?
- What does the value of an
(int)"string"
represent?Another example:
(int)("word" - "rd") = 6273 (int)("rd" - "word") = -6273 (int)("word" - " rd") = -5 (int)(" rd" - "word") = -5
Why does
(int)(".c" - __FILE__)
even work?
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__)
还有效?
同上,但这是另一个例子:
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__)
的字符串(少两个字符)
一个字符串(带双引号),例如"abc"
,在用作表达式 时被转换为指针。如果你给一个指针加上一个整数,你会得到一个新的指针。如果你减去两个兼容的指针,你会得到一个整数。
一个字符(带单引号),例如'x'
,只是一个整数。您可以像任何其他整数一样添加、减去它们等。
__FILE__
扩展为字符串,因此 ".c" - __FILE__
是两个指针相减所得的整数。
如果您将指针转换为一个整数,您将得到一个整数。
请记住,一些涉及指针的表达式可能没有明确定义,但数据类型是。
您的示例中发生了三件事。
首先在 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"
的字符串文字是指向字符串内容的 指针 。
发生的第三件事是您的linker 执行了重复字符串消除。它已详尽地搜索您的代码以查找相同的字符串文字,并用单个指针替换它们。您观察的这一部分取决于实现,可能不适用于所有工具链,甚至可能不适用于具有不同 compiler/linker 设置的同一工具链。
内置宏__FILE__
是一个字符串文字,包含实例化它的源文件的名称。在示例中:
(int)(".c" - __FILE__)
__FILE__
== "filename.c"
并且 linker 在其中找到重复的 ".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,但是除了在这种情况下 linker 可能与"rd"
与 " rd"
字符串的结尾而不是 "word"
的结尾。 linker 行为是实现定义的并且是不确定的。结果可能会有所不同,例如,如果您删除了第三个和第四个表达式以使字符串文字不再存在。可能会引用来自完全不同 link 模块的字符串。
重点是您不能完全依赖此 undefined/implementation 行为(字符串消除即指针算术和文字字符串指针行为已明确定义)。作为对 linker 行为的检查很有趣,但作为编程技术没有用。