简体   繁体   English

您如何在C语言中解释这个类似于函数的宏`slice`的输出?

[英]How do you explain the output from this function-like macro `slice` in C?

#include <stdio.h>

#define slice(bare_string,start_index) #bare_string+start_index
#define arcane_slice(bare_string,start_index) "ARCANE" #bare_string+start_index

int main(){
    printf("slice(FIRSTA,0)==> `%s`\n",slice(FIRSTA,0));
    printf("slice(SECOND,2)==> `%s`\n",slice(SECOND,2));
    printf("slice(THIRDA,5)==> `%s`\n",slice(THIRDA,5));
    printf("slice(FOURTH,6)==> `%s`\n",slice(FOURTH,6));
    printf("slice(FIFTHA,7)==> `%s`\n",slice(FIFTHA,7));
    printf("arcane_slice(FIRSTA,0)==> `%s`\n",arcane_slice(FIRST,0));
    printf("arcane_slice(SECOND,2)==> `%s`\n",arcane_slice(SECOND,2));
    printf("arcane_slice(THIRDA,5)==> `%s`\n",arcane_slice(THIRDA,5));
    printf("arcane_slice(FOURTH,6)==> `%s`\n",arcane_slice(FOURTH,6));
    printf("arcane_slice(FIFTHA,7)==> `%s`\n",arcane_slice(FIFTHA,7));
    return 0;
}

OUTPUT: OUTPUT:

slice(FIRSTA,0)==> `FIRSTA`
slice(SECOND,2)==> `COND`
slice(THIRDA,5)==> `A`
slice(FOURTH,6)==> ``
slice(FIFTHA,7)==> `slice(FIFTHA,7)==> `%s`
`
arcane_slice(FIRSTA,0)==> `ARCANEFIRST`
arcane_slice(SECOND,2)==> `CANESECOND`
arcane_slice(THIRDA,5)==> `ETHIRDA`
arcane_slice(FOURTH,6)==> `FOURTH`
arcane_slice(FIFTHA,7)==> `IFTHA`

I have the above C code that I need help on. 我有上面的C代码,需要帮助。 I am getting weird behaviour from 我从中得到奇怪的行为
the function-like macro slice that is supposed to 'slice' from a passed index 应该从传递的索引中“切片”的类似函数的宏slice
to the end of the string. 到字符串的末尾。 It does not slice in the real sense but passes 它不是真正意义上的切片而是通过
a pointer from a certain point to printf which starts printing from that 从某个点到printf的指针,该指针从该点开始打印
address. 地址。 I have managed to figure out that in arcane_slice the strings 我设法找出在arcane_slice的字符串
are concatenated first then 'sliced'. 先级联然后“切片”。 I also have figured out that when start_index 我也想通了,当start_index
is equal to 6 printf starts printing from the null byte and that is why 等于6 printf从空字节开始打印,这就是为什么
you get the 'empty' string. 您将获得“空”字符串。 The strange part is when start_index is 7. It prints 奇怪的是start_index为7时显示
the first argument to printf (interpolator string) concatendated with the passed bare string in both. printf的第一个参数(内插器字符串)与两者中传递的裸露字符串相结合。
arcane_slice and slice (as shown in the 5th and 10th lines in the output) arcane_sliceslice (如输出中的第5行和第10行所示)
Why is that so? 为什么会这样?
My wildest guess is that when the start_index exceeds the length of the strings, 我最疯狂的猜测是,当start_index超过字符串的长度时,
the pointer points to the start of the data segment in the program's address space. 指针指向程序地址空间中数据段的开头。 But
then you could counter that with "why didn't it start printing from FIRSTA " 那么您可以使用“为什么它不从FIRSTA开始打印”来进行FIRSTA

Not any "data segment", the stack. 没有任何“数据段”,堆栈。 This is what I remember: when C calls a function it first puts data on stack, first variable arguments, then the format, all being the addresses to the memory sequentially allocated with your text. 这就是我所记得的:当C调用一个函数时,它首先将数据放在堆栈上,第一个变量参数,然后是格式,所有这些都是随文本顺序分配的内存地址。 In that block of memory, the last argument (c-string) goes first, and the first goes last, thus: 在该内存块中,最后一个参数(c字符串)位于第一个,最后一个位于最后一个,因此:

Memory: 记忆:

"FIFTHA\0slice(FIFTHA,7)==> `%s`\n\0"

Arguments: 参数:

<pointer-to-"FIFTHA"> <pointer-to-"slice...">

Since you overincrement the first one it skips the '\\0' character and points at the format as well. 由于您过度增加了第一个字符,因此它会跳过'\\0'字符并指向格式。

Try to experiment with this with more placeholders, like 尝试使用更多占位符对此进行试验,例如

 printf("1: %s, 2: %s\n", slice(FIFTHA,7), slice(FIFTHA,6));
 slice(bare_string,start_index) #bare_string+start_index  

you are passing a string and bare_string stores the starting address of string which you have passed and then you returning changed pointer location which is bare_string+start_index 您正在传递一个stringbare_string存储已传递的string的起始地址,然后返回更改的指针位置,即bare_string+start_index

char str[6]="Hello";

char *ptr =str;

printf("%s\n",str);//prints hello

printf("%s\n",str+1);//prints ello
printf("%s\n",str+2);//prints llo
printf("%s\n",str+3);//prints lo
printf("%s\n",str+4);//prints o
printf("%s %c=%d  \n",str+5,*(str+5),*(str+5));//prints Null
printf("%s %c=%d  \n",str+6,*(str+6),*(str+6));//prints Null or may be Undefined behavior
printf("%s %c=%d  \n",str+7,*(str+7),*(str+7));//prints Null or may be Undefined behaviour

the same scenario is happing in your case. 您的情况也存在相同的情况。

Test Code: 测试代码:

#include<stdio.h>

main()
{
char str[6]="Hello";

char *ptr =str;

printf("%s\n",str);//prints hello

printf("%s\n",str+1);//prints ello
printf("%s\n",str+2);//prints llo
printf("%s\n",str+3);//prints lo
printf("%s\n",str+4);//prints o
printf("%s %c=%d  \n",str+5,*(str+5),*(str+5));//prints Null
printf("%s %c=%d  \n",str+6,*(str+6),*(str+6));//prints Null or may be Undefined behavior
printf("%s %c=%d  \n",str+7,*(str+7),*(str+7));//prints Null or may be Undefined behaviour

}

You have answered your question yourself. 您已经回答了自己的问题。 "FIFTHA"+7 gives you a pointer outside the string object, which is undefined behavior in C. "FIFTHA"+7为您提供了字符串对象外部的指针,这在C语言中是未定义的行为。

There's no easy way to get a more Python-like behavior for such "slices" in C. You could make it work for indexes up to a certain upper limit by adding a suffix to your string, full of zero bytes: 对于C中的此类“切片”,没有简单的方法来获得更像Python的行为。通过在字符串中添加一个后缀(零字节为零),可以使其在索引达到一定上限时起作用:

#define slice(bare_string,start_index) ((#bare_string "\0\0\0\0\0\0\0")+(start_index))

Also, when using macros, it's good practice (and avoids bugs too) to use parentheses excessively. 另外,使用宏时,过度使用括号是一种很好的做法(并且也避免了错误)。

#define slice(bare_string,start_index) ((#bare_string)+(start_index))
#define arcane_slice(bare_string,start_index) (("ARCANE" #bare_string)+(start_index))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM