使用带printf的双括号时出现分段错误

时间:2013-12-06 12:24:52

标签: c linux segmentation-fault printf comma-operator

#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(( ));

3 个答案:

答案 0 :(得分:11)

因为(a, b)实际上是单个值。它会计算ab并返回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知道将ab作为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);

注意逗号和五个如何移动到带括号的子表达式之外。