"str literal" + "str literal"
如何运作 了解'a' + 'b'
或'9' - '0' = 9
('字符' +'字符')的工作原理:
对于那些对C更熟悉的人,感谢您的阅读
(用clang编译,标准= C11)
示例:
(尝试在没有
__FILE__
扩展名的情况下打印".c"
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__)
的字符串(少两个字符)
答案 0 :(得分:1)
一个字符串(带双引号),例如"abc"
用作表达式时会转换为指针。如果向指针添加整数,则会得到一个新指针。如果你减去两个兼容的指针,你会得到一个整数。
一个字符(带单引号),例如'x'
,只是一个整数。您可以添加它们,减去它们等,就像任何其他整数一样。
__FILE__
扩展为字符串,因此".c" - __FILE__
是减去两个指针所得的整数。
如果将指针强制转换为整数,则会得到一个整数。
请记住,某些涉及指针的表达式可能没有明确定义,但数据类型是。
答案 1 :(得分:1)
您的示例中发生了三件事。
首先在C指针算术规则中,可以减去两个指针以产生两个指针之间的地址的差异。例如:
char test[2] ;
char* t1 = &test[0] ;
char* t2 = &test[1] ;
ptrdiff_t d = t2 - t1 ; // d == 1
其中ptrdiff_t
是一个整数类型,能够保持任何两个指针之间的差异。转换为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"
与" rd"
字符串的结尾,而不是"word"
的结尾。链接器行为是实现定义的和非确定性的。结果可能会有所不同,例如,如果删除了第三个和第四个表达式,以便不再存在字符串文字。可以引用来自完全不同的链接模块的字符串。
关键是你不能依赖于这个完全未定义的/实现行为(字符串消除 - 指向算术,文字字符串指针行为定义明确)。作为链接器行为的检查很有意思,但作为编程技术并不有用。