将值传递给函数时,GCC前缀增量运算符行为不端[重复]
Posted
技术标签:
【中文标题】将值传递给函数时,GCC前缀增量运算符行为不端[重复]【英文标题】:GCC prefix increment operator misbehaving when passing value to the function [duplicate] 【发布时间】:2016-04-21 10:17:03 【问题描述】:使用 GCC 编译时,前缀增量运算符不会在调用 printf()
时发送变量 (x) 的增量值。
这是我的代码;
#include <stdio.h>
int bitcount(unsigned);
int main()
unsigned int x = 127;
printf("bitcount[%d] : %d\n", x, bitcount(x));
printf("bitcount[%d] : %d\n", ++x, bitcount(x));
return 0;
int bitcount(unsigned int x)
int bitcount = 0;
for(; x != 0; x >>= 1)
if( x & 1 )
bitcount++;
return bitcount;
在main()方法中,问题出在下面一行;
printf("bitcount[%d] : %d\n", ++x, bitcount(x));
X 应该增加并发送到bitcount()
,x 的增加值。但是 x 的值会增加,而不是增加的值,而是将旧值发送到 bitcount()
函数。
我在 MS VS 上尝试过同样的事情,但没有发生这种行为不端。输出如下;
在 Windows 10 上使用 GCC 编译的程序输出
D:\C\chapter2>gcc bitcount.c -o bitcount.exe
D:\C\chapter2>bitcount
bitcount[127] : 7
bitcount[128] : 7
在 Windows 10 上使用 MS VS 编译的程序输出
bitcount[127] : 7
bitcount[128] : 1
为了解决这个问题,我更新了代码以查看发送到函数的值;
Bitcount V2
#include <stdio.h>
int bitcount(unsigned);
int main()
unsigned int x = 127;
printf("bitcount[%d] : %d\n", x, bitcount(x));
printf("bitcount[%d] : %d\n", ++x, bitcount(x));
return 0;
int bitcount(unsigned int x)
printf("\nDebug::\tbitcount()::x=%d\n", x);
int bitcount = 0;
for(; x != 0; x >>= 1)
if( x & 1 )
bitcount++;
return bitcount;
在 Windows 10 系统上使用 GCC 编译的 Bitcount v2 输出
调试::bitcount()::x=127 位计数[127]:7
调试::bitcount()::x=127 位计数[128]:7
很明显,GCC 将 X 的旧值发送到 bitcount() 函数。
为了概括问题,我写了下面的程序;
InsideFunc.c
#include <stdio.h>
int func(unsigned);
int main()
unsigned int x = 127;
printf("x: %d, func(): %d\n", x, func(x));
printf("x: %d, func(): %d\n", ++x, func(x));
return 0;
int func(unsigned x)
printf("\n\tDebug::func()::x=%d\n", x);
return x;
在 Windows 10 系统上使用 GCC 编译的输出
D:\C\chapter2>gcc InsideFunc.c -o InsideFunc.exe
D:\C\chapter2>InsideFunc
Debug::func()::x=127
x:127,函数():127
Debug::func()::x=127
x:128,函数():127
同样,变量的值增加,但旧值发送到函数。
这是我的 gcc 版本;
D:\C\chapter2>gcc --version
gcc (GCC) 5.2.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
有什么想法吗?
后期说明:我刚刚在 Kernighan & Ritchie 的 The C Programming Language 一书中看到,第 49 页解释了顺序函数参数中的求值是不确定的,并且依赖于编译器;
同样,函数参数的计算顺序不是 指定,所以声明
printf("%d %d\n", ++n, power(2, n)); /*WRONG */
使用不同的编译器可能会产生不同的结果,具体取决于 n 在调用 power 之前是否递增。的解决方案, 当然是写
++n;
printf("%d %d\n", n, power(2, n));
【问题讨论】:
UB,因为函数参数评估和传递约定没有排序。 Possible dupe 我不认为这是一个重复的问题。将递增的值传递给函数时会出现此问题。bitcount[%d]
--> bitcount[%u]
@LeventDivilioglu 它与 Sourav 链接的问题重复。你在同一个表达式中使用了两次x
,中间没有序列点,并且有一个未排序的副作用x
。一旦修复了该错误,可能还会出现函数参数评估顺序的问题。
【参考方案1】:
函数调用参数的求值顺序在 C++ 中未指定,因此如下行:
printf("bitcount[%d] : %d\n", ++x, bitcount(x));
不能保证++x
会在bitcount(x)
之前被评估,所以bitcount
可以通过x
预递增。您所有的编译器都有不同但有效(即符合标准)的行为。
【讨论】:
行为未定义。 x 在没有序列点的情况下被修改和读取。 确实未指定参数的评估顺序。但这个表达式的意义远不止于此:x
在序列点之间被多次使用,除了确定在x
中存储哪个值之外,还有其他目的。那是未定义的行为。所以在这个例子中,你有未定义和未指定的行为。前者总是一个严重的错误,后者如果程序依赖于顺序可能会导致错误。
这不是重复的,问题也不是未定义的行为。更相关的是如何调用printf函数以及调用printf之前如何创建激活记录。创建激活记录时,编译器开始从右向左推送 printf 变量;因此,首先在 x 递增并入栈之前调用 bitcount 函数,然后 x 递增并入栈。
@merkez3110 不,这根本不正确。请参阅 C99 6.5“在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。此外,应只读先前的值以确定要存储的值。”然后另请参阅 6.5.2.2/10“未指定函数指示符、实际参数和实际参数中的子表达式的求值顺序”。
我会坚持:考虑像int foo(int x) return (x * x);
这样的 foo 函数,它只返回 x 的平方。当main()
代码行是int x = 2; printf("x = %d foo(x) = %d\n", ++x, foo(x));
并且您只需通过gcc a.c -o a.exe
行编译它,代码编译并运行正常,吐出x = 3 foo(x) = 4
。但是,当通过gcc a.c -Wall -Werror -o a.exe
行编译相同的代码时,您会收到类似“对'x' 的操作可能未定义”的警告。因此,很明显,未定义的行为与 printf 变量压入堆栈的顺序有关。【参考方案2】:
不要在表达式中使用自增:
printf("bitcount[%d] : %d\n", x, bitcount(x));
x++;
printf("bitcount[%d] : %d\n", x, bitcount(x));
【讨论】:
以上是关于将值传递给函数时,GCC前缀增量运算符行为不端[重复]的主要内容,如果未能解决你的问题,请参考以下文章