简体   繁体   English

在 c 中使用 stringize 运算符时出现问题

[英]problem while using stringize operator in c

#define str(n) n
puts(str(hello));

The above piece of code is working fine in c but the below mentioned code is not giving any output in the console上面的代码在 c 中运行良好,但下面提到的代码在控制台中没有给出任何 output

#define str(n) #n
char* name="David";
puts(strcat(str(hello ),name));

can anyone help me to figure out what is wrong with the second piece of code and please let me know in which cases we can use '#' operator in c and when we shouldn't use that???谁能帮我弄清楚第二段代码有什么问题,请告诉我在哪些情况下我们可以在 c 中使用“#”运算符,什么时候不应该使用它???

The issue with the code presented in the question doesn't have anything to do with the stringification operator in particular.问题中出现的代码问题与字符串化运算符没有任何关系。 Rather, your use of strcat() is invalid.相反,您对strcat()的使用无效。

Remember that stringification produces a string literal , so this...记住 stringification 产生一个string literal ,所以这......

 #define str(n) #n char* name="David"; puts(strcat(str(hello ),name));

... is equivalent to this... ...相当于这个...

#define str(n) #n
char* name="David";
puts(strcat("hello",name));

strcat attempts to write data into the array specified by the first argument, starting at the position of the string terminator. strcat尝试将数据写入第一个参数指定的数组,从字符串终止符的 position 开始。 There are at least three preconditions:至少有三个前提条件:

  1. The destination array must be modifiable.目标数组必须是可修改的。
  2. The destination array must contain a string terminator.目标数组必须包含字符串终止符。
  3. There must be enough unused space at the end of the array to accommodate the additional characters.数组末尾必须有足够的未使用空间来容纳额外的字符。

A string literal is not modifiable and does not contain any extra space, so conditions (1) and (3) are never met when the first argument to strcat() is a string literal.字符串文字不可修改且不包含任何额外空格,因此当strcat()的第一个参数是字符串文字时,条件 (1) 和 (3) 永远不会满足。 Undefined behavior results from such a call.此类调用会导致未定义的行为。

str(hello) or str(hello ) is the string literal "hello" . str(hello)str(hello )是字符串文字"hello" In passing, note that the trailing space character is not included :顺便说一句,请注意不包括尾随空格字符

If, in the replacement list, a parameter is immediately preceded by a # preprocessing token, both are replaced by a single character string literal preprocessing token that contains the spelling of the preprocessing token sequence for the corresponding argument.如果在替换列表中,参数前面紧跟着一个 # 预处理标记,则两者都将替换为单个字符串文字预处理标记,其中包含相应参数的预处理标记序列的拼写。 Each occurrence of white space between the argument's preprocessing tokens becomes a single space character in the character string literal.参数的预处理标记之间每次出现的空格都会成为字符串文字中的单个空格字符。 White space before the first preprocessing token and after the last preprocessing token composing the argument is deleted.删除构成参数的第一个预处理标记之前和最后一个预处理标记之后的空白。

(6.10.3.2 The # operator, C99). (6.10.3.2 # 运算符,C99)。

In memory this is 'h' , followed by 'e' , ..., followed by 'o' , followed by the null character (a byte with all bits set to 0, typically represented by '\0' ):在 memory 中,这是'h' ,然后是'e' ,...,然后是'o' ,然后是 null 字符(所有位都设置为 0 的字节,通常用'\0'表示):

'h' 'e' 'l' 'l' 'o' '\0' 'h' 'e' 'l' 'l' 'o' '\0'

When you apply strcat like that, it tries to replace '\0' with a 'D'当你像那样应用strcat时,它会尝试用'D'替换'\0' '

'h' 'e' 'l' 'l' 'o' 'D' '你好ð'

then make the subsequent bytes 'a' , 'v' , ..., 'd' , '\0' :然后制作后续字节'a''v' ,..., 'd''\0'

'h' 'e' 'l' 'l' 'o' 'D' 'a' 'v' 'i' 'd' '\0' 'h' 'e' 'l' 'l' 'o' 'D' 'a' 'v' 'i' 'd' '\0'

At least two problems with this:这至少有两个问题

  • bytes after the '\0' have probably not been allocated to you! '\0'之后的字节可能没有分配给你!
  • it is considered undefined behavior if (quote from C99 Standard)如果(引用自 C99 标准),它被认为是未定义的行为

[t]he program attempts to modify a string literal. [t] 程序试图修改字符串文字。

For reference, from the C99 Standard, the strcat function has the prototype作为参考,来自C99标准, strcat function有原型

#include <string.h>
char *strcat(char * restrict s1, const char * restrict s2);

and description和描述

The strcat function appends a copy of the string pointed to by s2 (including the terminating null character) to the end of the string pointed to by s1. strcat function 将 s2 指向的字符串的副本(包括终止字符 null)附加到 s1 指向的字符串的末尾。 The initial character of s2 overwrites the null character at the end of s1. s2 的起始字符覆盖了 s1 末尾的 null 字符。 If copying takes place between objects that overlap, the behavior is undefined.如果复制发生在重叠的对象之间,则行为未定义。

You should place "Hello" in a char array large enough to also store the name that you want to concatenate if you want your desired output. For example,如果您想要所需的 output,您应该将"Hello"放在一个足够大的char数组中,以便还可以存储要连接的名称。例如,

#include <stdio.h>
#include <string.h>

#define STRINGIZE(x) #x

int main(void) {

    char *name = "David";
    char a[12] = STRINGIZE(Hello) " ";

    puts(strcat(a, name)); 

    return 0;

}

Output Output

Hello David

The character array, a , has 12 elements so that it can contain all 5 characters in Hello , the space character,字符数组a有 12 个元素,因此它可以包含Hello中的所有 5 个字符,即空格字符, , all 5 characters in David , plus the null character. , David中的所有 5 个字符,加上 null 字符。

Note that 12 is the minimum length for the array a to hold the string "Hello David" (11 characters plus 1 for the null character).请注意,12 是数组a保存字符串"Hello David"最小长度(11 个字符加上 null 字符的 1)。 You will need a to be larger if the names will be larger.如果名称更大,则需要a If you know, from your input, the largest possible name, then you can make a large enough to hold the largest possible name (plus Hello plus the null character).如果您从输入中知道最大的可能名称,那么您可以创建a足够大的名称来容纳最大的可能名称(加上Hello加上 null 字符)。

Alternatively, first, you decide on some arbitrary length for the array a .或者,首先,您决定数组a任意长度。 Then, you use the strncat function in a safe way such that strncat only writes to elements of the array a .然后,以安全的方式使用strncat function,这样strncat只写入数组a元素。 The strncat function essentially does the same thing as strcat except it allows you to specify a third argument which represents the maximum number of characters from s2 to append to s1 (the null character that strncat automatically appends to the result of the concatenation is not included in this number). strncat function 本质上与strcat做同样的事情,除了它允许您指定第三个参数,该参数表示从s2到 append 到s1的最大字符数( strncat自动附加到串联结果的 null 字符不包括在这个号码)。 In the case that you specify a third argument that instructs strncat to never write past the end of the array a , if the name is too long, the full name will not be stored in a , but this is better and safer than trying to write past the end of the array, which is what strcat would have attempted.如果您指定第三个参数来指示strncat永远不会写入数组末尾a之后,如果名称太长,则不会将全名存储在a中,但这比尝试编写更好更安全超过数组的末尾,这是strcat会尝试的。

Again, for reference (from C99 Standard), the strncat function has the prototype同样,作为参考(来自 C99 标准), strncat function 具有原型

#include <string.h>
char *strncat(char * restrict s1, const char * restrict s2,
              size_t n);

and description和描述

The strncat function appends not more than n characters (a null character and characters that follow it are not appended) from the array pointed to by s2 to the end of the string pointed to by s1. strncat function 从 s2 指向的数组到 s1 指向的字符串的末尾追加不超过 n 个字符(一个 null 字符及其后面的字符不追加)。 The initial character of s2 overwrites the null character at the end of s1. s2 的起始字符覆盖了 s1 末尾的 null 字符。 A terminating null character is always appended to the result.终止字符 null 始终附加到结果。 If copying takes place between objects that overlap, the behavior is undefined.如果复制发生在重叠的对象之间,则行为未定义。

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

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