使用带有 printf 的双括号时出现分段错误 [重复]

Posted

技术标签:

【中文标题】使用带有 printf 的双括号时出现分段错误 [重复]【英文标题】:segmentation fault when using double brackets with printf [duplicate] 【发布时间】:2013-12-23 19:16:15 【问题描述】:
#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(( ));?

【问题讨论】:

【参考方案1】:

因为(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 的值)应作为单个参数发送到func

如果您在编译时出现警告,并且您的编译器对您很好,它可能会就此发出警告。如果你的编译器不好,它仍然应该抱怨你给了一个int,而应该是const char *

如果使用gcc,我强烈建议始终使用-Wall 进行编译。

【讨论】:

【参考方案2】:

你在不知不觉中使用了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-expression ( argument-expression-listopt )
argument-expression-list:
   assignment-expression
   argument-expression-list , assignment-expression
                            ^

, 只是函数调用中的分隔符。

启用警告应该在这里有所帮助,gcc 给了我一些关于这个程序的警告:

警告:逗号表达式的左操作数无效[-Wunused-value]

警告:传递 'printf' 的参数 1 使指针从整数而不进行强制转换 [默认启用] 注意:预期为 'const char * restrict' 但参数的类型为 'int'

【讨论】:

@minitech 感谢您的语法修复,有什么特别的理由更喜欢使用[]() 链接吗? 它更短,看起来更好,但重要的变化是使用 HTTPS 版本的***。没问题! @minitech 嗯,我们为什么要使用 HTTPS 版本?【参考方案3】:

这是因为 printf 是一个函数,它将接受单括号中的参数,而第二组括号实际上是打开了一个子表达式:

(string "string" string "string" , 5)

前四个字符串在编译时连接起来,产生:

("string", 5)

然后对其进行评估:

"string" 计算为指向它的第一个字符的指针 a,b 先计算 a,然后将结果扔掉,然后计算并返回 b 5 计算为整数常量 5

所以实际上,你在打电话:

printf(5);

(这是因为字符串没有副作用。)

然而,这样的事情会起作用:

printf((POOLNAME_FMT "Cannot allocate %d bytes" POOLNAME_FMT "in pool not enough memory"),5);

注意逗号和 5 是如何移到带括号的子表达式之外的。

【讨论】:

以上是关于使用带有 printf 的双括号时出现分段错误 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

设置堆栈后在 C 中调用 printf 时出现分段错误

访问结构时出现分段错误

使用带有无法识别的长选项的“getopt_long”时出现分段错误

为啥在访问二级指针时出现分段错误错误? C语言

弹出 x86 堆栈时出现分段错误

打印指针时出现分段错误