#include<stdio.h>
#define POOLNAME_FMT "Hello"
void main() {
printf((POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory",5));
}
为什么当我将双括号与printf
. 即printf(( ));
?
#include<stdio.h>
#define POOLNAME_FMT "Hello"
void main() {
printf((POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory",5));
}
为什么当我将双括号与printf
. 即printf(( ));
?
因为(a, b)
实际上是一个单一的值。它计算a
并b
返回 的值b
。
所以你在做的基本上是:
/* calculate before `,` and ignore */
POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory";
/* call printf with after `,` */
printf(5);
这显然是错误的。
当您编写func(a, b)
为函数调用时,C 知道将a
和b
作为单独的参数发送到func
. 当您说 时func((a, b))
,您明确地说(a, b)
是一个值,并且结果(即 的值b
)应该func
作为单个参数发送到。
如果您在编译时出现警告,并且您的编译器对您很好,它可能会就此向您发出警告。如果你的编译器不好,它仍然应该抱怨你给出了int
一个const char *
预期的地方。
如果使用gcc
,我强烈建议-Wall
始终使用 进行编译。
您正在使用逗号运算符而没有意识到:
( ... "in pool not enough memory",5)
^
由于逗号运算符将评估其左操作数并丢弃结果,然后评估并返回右操作数,因此您最终得到:
printf( 5 ) ;
它将尝试将格式字符串转换int
为 a const char *restrict
,这几乎肯定不会指向有效内存。如果没有()
, the,
将只是函数参数的分隔符。
在这种()
情况下是一个表达式;如果我们查看C99 草案标准部分6.5.1
Primary expressions,我们有:
( expression )
因此,当我们可以从Postfix 运算符,
部分看到时,将其视为运算符:6.5.2
postfix-expression ( argument-expression-listopt )
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression
^
这,
只是函数调用中的分隔符。
启用警告应该在这里有所帮助,gcc
给我一些关于这个程序的警告:
警告:逗号表达式的左侧操作数无效 [-Wunused-value]
和
警告:传递 'printf' 的参数 1 使指针从没有强制转换的整数 [默认启用] 注意:预期的 'const char * restrict' 但参数的类型为 'int'
这是因为 printf 是一个函数,它将接受单括号中的参数,而第二组括号实际上是打开一个子表达式:
(string "string" string "string" , 5)
前四个字符串在编译时连接起来,产生:
("string", 5)
然后评估:
"string"
计算为指向它的第一个字符的指针,
b首先计算a,然后将结果丢弃,然后计算并返回b5
计算为整数常量 5因此,实际上,您正在调用:
printf(5);
(这是因为字符串没有副作用。)
然而,这样的事情会起作用:
printf((POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory"),5);
注意逗号和 5 是如何移到带括号的子表达式之外的。