简体   繁体   English

使用 %s 说明符时,可以将 int 数组传递给 scanf 和 printf 吗?

[英]Is it ok to pass an int array to scanf and printf when using the %s specifier?

I stumbled upon a question with this code我偶然发现了这个代码的问题

int arr[10];
scanf("%s", arr);
printf("%s", arr);

I don't know the purpose, and I'm perfectly aware of how much this code smells.我不知道目的,但我完全清楚这段代码的味道。 But my question here is if this i legal, and if I can expect it to reprint the string I enter?但我的问题是这是否合法,我是否可以期望它重印我输入的字符串? (Provided that the input string isn't so long that it causes buffer overflow) (前提是输入的字符串不是太长导致缓冲区溢出)

And I also wonder if there's any example where this is actually useful.我还想知道是否有任何实际有用的示例。

From the C standard about fprintf https://port70.net/%7Ensz/c/c11/n1570.html#7.21.6.1p8来自C关于fprintf的标准https://port70.net/%7Ensz/c/c11/n1570.html#7.21.6.1p8

If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.如果不存在 l 长度修饰符,则参数应为指向字符类型数组的初始元素的指针。

and fscanf https://port70.net/%7Ensz/c/c11/n1570.html#7.21.6.2p12和 fscanf https://port70.net/%7Ensz/c/c11/n1570.html#7.21.6.2p12

If no l length modifier is present, the corresponding argument shall be a pointer to the initial element of a character array large enough to accept the sequence and a terminating null character, which will be added automatically.如果不存在 l 长度修饰符,则相应的参数应是指向字符数组的初始元素的指针,该字符数组的大小足以接受序列和终止字符 null,该字符将自动添加。

And in this case, it's not a character array.在这种情况下,它不是字符数组。 But I seem to recall that there are some special rules about implicit conversions to and from char pointers, but I also have a memory that these does not apply to variadic functions.但我似乎记得有一些关于与 char 指针的隐式转换的特殊规则,但我也有一个 memory 这些不适用于可变参数函数。

For the language lawyer I would say it is illegal:对于语言律师,我会说这是非法的:

From C11: 7.21.6.来自 C11:7.21.6。

s If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type . s如果不存在l长度修饰符,则参数应为指向字符类型数组的初始元素的指针 280) 280)

and

9 If a conversion specification is invalid, the behavior is undefined. 9 如果转换规范无效,则行为未定义。 282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined. 282)如果任何参数不是相应转换规范的正确类型,则行为未定义。

For any practical use I would say that I cannot think of a scenario where it might fail as long as you don't enter more characters than fit into the array.对于任何实际用途,我会说,只要您输入的字符数不多于适合数组的字符数,我想不出它可能会失败的场景。

Update after question was extended:问题扩展后的更新:

But I seem to recall that there are some special rules about implicit conversions to and from char pointers, but I also have a memory that these does not apply to variadic functions.但我似乎记得有一些关于与 char 指针的隐式转换的特殊规则,但我也有一个 memory 这些不适用于可变参数函数。

Correct, implicit conversions can only happen if type of destination is known.正确的隐式转换只有在目标类型已知的情况下才会发生。 For variadic functions no such conversion is done for pointers.对于可变参数函数,指针不会进行此类转换。

And also in those cases where an implicit conversion would be done, it is only possible if one of them is void * , not between int * and char * .而且在那些将进行隐式转换的情况下,只有其中之一是void *才有可能,而不是在int *char *之间。

... that there are some special rules about implicit conversions to and from char pointers ...关于与 char 指针的隐式转换有一些特殊规则

No, that's not correct.不,那是不正确的。

For void pointers you have implicit conversion but not for char pointers.对于 void 指针,您有隐式转换,但对于 char 指针则没有。 In the very old K&R days (ie before "void" was introduced) char pointers were used as "the generic pointer" type but still there was no implicit conversion.在非常古老的 K&R 时代(即在引入“void”之前),char 指针被用作“通用指针”类型,但仍然没有隐式转换。

Maybe you are confusing conversion with aliasing.也许您将转换与别名混淆了。 For aliasing char pointers are special as a char pointer is allowed to alias other object types.对于别名 char 指针是特殊的,因为允许 char 指针别名其他 object 类型。

The conclusion is that the code has undefined behavior.结论是代码具有未定义的行为。 Passing an int pointer when a char pointer is expected is not standard compliant.在需要 char 指针时传递 int 指针不符合标准。

You are allowed to access an int or an array of int using char references;您可以使用char引用访问intint数组; C 2018 6.5 7 says character types may be used to access an object. C 2018 6.5 7 表示字符类型可用于访问 object。

However, for %s , scanf and printf should be passed a char * , not an int * .但是,对于%sscanfprintf应该传递一个char * ,而不是一个int * Even though a char * may be used (with dereferencing) to access an int or array of int , that does not mean an int * will serve in place of a char * .即使可以使用char * (取消引用)来访问intint数组,但这并不意味着int *将代替char * When scanf or printf attempts to get the char * they expect (as by using va_arg ), the fact that an int * was passed makes the behavior not defined by the C standard.scanfprintf尝试获取他们期望的char *时(通过使用va_arg ),传递int *的事实使得行为未由 C 标准定义。

If instead you convert the int * to a char * :相反,如果您将int *转换为char *

scanf("%s", (char *) arr);
printf("%s", (char *) arr);

then the behavior is arguably defined by the C standard.那么该行为可以说是由 C 标准定义的。 (“Arguably” because the internals of scanf and printf are not formally specified. Presumably they align with the aliasing rules in 6.5 7.) (“可以说是”因为scanfprintf的内部没有正式指定。大概它们与 6.5 7 中的别名规则一致。)

The program will run but with a warning explaining that %s expects the variable arr to be a char * type otherwise an array of char .该程序将运行,但会出现一条警告,说明%s期望变量arrchar *类型,否则为char数组。 So, the output will be the string that the user types on demand of the program...因此,output 将是用户根据程序要求键入的字符串...

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

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