我想知道< code>printf("%d ",x)到底是怎么解释的。我只知道编译器会保留一个内存来存放< code>'%',< code>'%d',< code>'\0',并将它的地址返回给< code>printf,然后根据我们指定的格式说明符打印第二个参数< code>x。
因此,如果我使用例如int x=5; char*p="%d"; printf(p, x)
,它是否与printf("%d", x)
相同?
C的一个有点奇怪的方面是,printf
函数虽然是一个不寻常的函数,但仍然是一个非常多的函数,所以所有通常的规则都适用。对于任何函数 f()
,如果你有一个带有复杂参数的调用,比如
f(complicatedargument1, arg2, arg3);
您可以随时将其更改为
sometype tmp = complicatedargument1;
f(tmp, arg2, arg3);
如果你还没有学过,你一定会在某个时候学的:C语言(和大多数编程语言)中的表达式非常非常通用。所以你不能只拥有
a + b
你可以有
(arbitrarily-complicated expression with many subexpressions) + (arbitrarily-complicated expression with many subexpressions)
您不仅可以拥有
f(a, b, c)
你也可以拥有
f((complicated subexpression), (another complicated subexpression), (yet another complicated subexpression))
(如果你想变得非常疯狂,事实证明你也可以用一个复杂的子表达式替换f
。)
因为表达是如此的笼统,所以你第二个问题的答案只能是“是”。
所以原则上写没有错
char *p = "%d";
int x = 5;
printf(p, x);
这确实会像你写的那样
printf("%d", x);
要非常清楚:这是有效的,因为printf
的第一个参数是一个字符串。绝大多数情况下,它是一个常量字符串,但没有理由它不可能是“string”类型的其他表达式,例如变量p
。(脚注:C实际上没有“字符串”类型,但这是一个单独的主题,我宁愿现在不讨论。
然而,在实践中,有一两个差异,与printf
是奇特的事实有关。
一个问题是,由于在调用printf
时可能会犯很多容易的错误,因此优秀的编译器会尝试通过检查其中一些错误来帮助您。如果您不小心写了
int x = 5;
printf("%f", x);
这行不通,gcc很有帮助地说:“警告:格式'%f'需要'double'类型的参数,但参数2的类型为'int'”。这是编译器所做的非常特殊的事情,但通常只有当printf
的第一个参数是字符串文字时,它才能这样做。如果你要写
int x = 5;
char *p = "%f"
printf(p, x);
编译器可能无法为您执行此检查。
另一个问题是打印F可能是危险的。偶尔,您可能正在做一些奇特的事情,您想在不同情况下使用不同格式的字符串,如下所示:
int x = 123;
char *p;
if(somecondition)
p = "%x\n";
else p = "%d\n";
printf(p, x);
根据somecondition
,这将以十进制或十六进制打印x。这很好,但如果你真的疯了,写下:
int x = 123;
char fmt[20];
printf("What format would you like to use? ");
fgets(fmt, 20, stdin);
printf(fmt, x);
现在用户实际上可以输入< code>printf
将要使用的格式字符串了!这个也可以,你可能想现在输入它,然后玩玩它。
…如果你感觉很冒险,你确实输入了它,在使用%d
、%x
嗯,%n
是printf
的一个非常特殊的格式说明符,它可以让您找出到目前为止打印了多少个字符。但是%n
的相应参数必须是指向int的指针。所以在这种情况下,它会错误地将x
的值解释为指针,这意味着它试图写入位置123之类的东西,这是非法的,并导致崩溃。
所以,这里的底线是使用常量字符串文字以外的东西作为printf
的第一个参数是有风险的,因为编译器将无法检查错误。如果格式字符串最终来自不受控制的东西,比如用户输入,这可能是非常危险的。
所以一般来说,最好不要充分利用这种自由。也就是说,最好将大部分或所有printf格式字符串保留为常量字符串文字。如果你在那里使用任意表达式,要小心,因为编译器无法检查它。除非你绝对确定你可以信任你的用户,否则不要让他们指定你的程序将使用的printf格式,因为这会让他们崩溃,甚至可能破坏你的程序。
因此,一些样式指南要求< code>printf的第一个参数是一个字符串。也见这个问题。
printf(“%d”,x)
是如何解释的?
OP的解释是对代码的一种潜在的部分描述。
然而,C和C通常是编译的,而不是解释的。今天的编译器可以检查 printf(“%d”,x)
并发出像 print_an_integer(x);
这样的代码。
在OP的示例中,2个代码在功能上是相同的,但编译器可能无法识别优化潜力,如上面所述的第一个代码。
int x=5;
// In C++, should be `const char *p="%d";`
char *p="%d";
printf(p,x);
// same as ????
printf("%d",x);
相反,处理传递给printf()
的格式字符串,寻找要打印和打印说明符的字符。打印说明符反过来获取下一个参数并相应地处理它们。
如果格式字符串和参数不匹配,如< code>printf("%f ",x)或< code > p = " % dprintf(p,5.0),结果是未定义的行为。
...具体如何...
编译器在生成发出的代码方面可以有很大的自由度。它需要满足虚拟机的等效功能需求,而不是OP的解释。任何准确的解释都取决于编译器和代码。
我需要在服务器端区分本地和远程CUPS打印作业。我认为可以使用打印作业的原始主机,但我无法找到可靠获取其值的方法,最接近的是IPP作业属性之一“作业原始主机名”,但当我用“ipptool”检查从一个主机打印到另一个主机的暂停作业时,它是空的。“lpq”报告与“localhost”相同的作业,因此也没有多大帮助。 这是用于虚拟OS X打印机的自定义CUPS后端部分,但如果您知道如何获取此信息,这可能
本文向大家介绍Java如何调用TSC打印机进行打印详解,包括了Java如何调用TSC打印机进行打印详解的使用技巧和注意事项,需要的朋友参考一下 前言 最近项目中用到了打印机,最开始的完全不懂,现在弄好了,所以做了总结,该篇包括后台的调用打印(两种方式)跟前端的js的打印,但是只有IE现在支持打印,而且如果想远程连接打印机,二维码的生成和直接由打印机的命令进行操作,就要把修改浏览器的安全配置,下面再
我编写的代码获取数组的元素,并遍历数组以给出所有排列。但我需要它只显示一定数量的排列: 最后的代码是只给出9个元素的6个排列(换句话说,打印总362880个输出中的前60480个排列)。为简单起见,我正在使用数组中的4个元素,并且我得到了所有24个排列以打印出来。但是我需要代码可以用于任意数量的排列。例如,如果我需要它打印出1-perMutation,代码应该打印前4个排列——ABCD、ABDC、
我试图在远程服务器上使用pgAdmin中的psql控制台和sql转储文件恢复架构。我收到以下错误: 由于缺乏超级用户权限,我似乎无法打印目录列表。 是否有方法在psql控制台中标识或打印当前工作目录?默认目录是什么?
问题内容: 搜索过,但没有找到满意的答案。 我知道没有可移植的方式来打印pthread_t。 您如何在您的应用程序中做到这一点? 更新: 实际上,我不需要pthread_t,但是需要一些小的数字ID,以便在调试消息中标识不同的线程。 在我的系统(64位RHEL 5.3)上,它被定义为unsigned long int,因此它的数量很大,仅打印它就在调试行中占据了宝贵的位置。 gdb 如何 分配 短
我正在尝试在删除第一个实例“c”“C”“d”或“D”的情况下打印aLine。但是,我仅限于使用String的indexOf、charAt、长度、compareTo、toUpperCase、toLowerCase、trim、equals、equalsIgnoreCase和子字符串方法。假设您可以输入任何您喜欢的字符串。 我已经实现了删除“c”。但是,如果“c”之前有“d”,它仍然会删除“c”。我已经