#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(( ));
?
答案 0 :(得分:11)
因为(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
的值)应发送给{{ 1}}作为一个参数。
如果您使用警告编译,并且您的编译器对您很好,它可能会警告您这一点。如果你的编译器不好,它仍然会抱怨你给func
预期int
。
如果使用const char *
,我强烈建议您始终使用gcc
进行编译。
答案 1 :(得分:8)
你正在使用comma operator而没有意识到:
( ... "in pool not enough memory",5)
^
因为逗号运算符将评估其左操作数并丢弃结果,然后计算并返回正确的操作数,最终得到:
printf( 5 ) ;
会尝试将int
转换为const char *restrict
格式字符串,这几乎肯定不会指向有效内存。如果没有()
,,
就会成为函数参数的分隔符。
()
是这种情况下的表达;如果我们查看C99 draft standard部分6.5.1
主要表达式,我们会:
( expression )
因此,
被视为运算符,而我们可以从6.5.2
Postfix运算符部分看到:
postfix-expression ( argument-expression-listopt )
argument-expression-list:
assignment-expression
argument-expression-list , assignment-expression
^
,
只是函数调用中的一个分隔符。
启用警告应该有帮助,gcc
给了我一些警告:
警告:逗号表达式的左侧操作数无效[-Wunused-value]
和
警告:传递'printf'的参数1使得整数指针没有强制转换[默认启用] 注意:预期'const char * restrict'但参数类型为'int'
答案 2 :(得分:2)
这是因为printf是一个函数,它将在单个parents中接受它的参数,而第二组parenthesēs实际上是在打开一个子表达式:
(string "string" string "string" , 5)
前四个字符串在编译时连接在一起,产生:
("string", 5)
然后评估:
"string"
计算指向其第一个字符的指针,
b 首先评估 a ,然后抛弃结果,然后评估并返回 b < / em>的5
计算为整数常数5 因此,实际上,您正在致电:
printf(5);
(这是因为字符串没有副作用。)
然而,这样的事情会起作用:
printf((POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory"),5);
注意逗号和五个如何移动到带括号的子表达式之外。