怎么" str" - " str"在C工作?它们是如何存储的?

时间:2017-11-18 08:15:07

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

免责声明:此问题询问"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__)的字符串(少两个字符)

2 个答案:

答案 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"的结尾。链接器行为是实现定义的和非确定性的。结果可能会有所不同,例如,如果删除了第三个和第四个表达式,以便不再存在字符串文字。可以引用来自完全不同的链接模块的字符串。

关键是你不能依赖于这个完全未定义的/实现行为(字符串消除 - 指向算术,文字字符串指针行为定义明确)。作为链接器行为的检查很有意思,但作为编程技术并不有用。