#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
转换为格式字符串的const char *restrict
,这几乎肯定不会指向有效的内存。 如果没有()
,那么这个函数参数就是分隔符。
()
是这个上下文中的表达式; 如果我们看看C99草案标准部分6.5.1
主要表达式 ,我们有:
( expression )
因此,
我们可以从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是一个函数,它将在单个括号中接受它的参数,而第二个parenthess实际上是打开一个子表达式:
(string "string" string "string" , 5)
前四个字符串在编译时连接在一起,产生:
("string", 5)
然后评估:
"string"
计算结果是一个指向它的第一个字符的指针 ,
b先评估一个 ,然后抛出结果,然后评估和返回b 5
评估为一个整数常数5 所以实际上,你打电话给:
printf(5);
(这是因为字符串没有副作用。)
然而,像这样的东西可以工作:
printf((POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory"),5);
注意逗号和五个是如何移到括号内的子表达式之外的。