如何解决有人可以解释 C 使用 #define UMAX (a, b) ((a) > (b) ? (a) : (b)) 指令的硬逻辑错误,该指令返回较低的值,在 2 个编译器中
我正在尝试找出发生在 MUD c 代码库上的错误的原因。 #define UMAX(a,b) ((a) > (b) ? (a) : (b)) 的使用用于返回两个值的最大值。 有时会返回较低的值,甚至调试我也找不到原因。
我隔离了用于复制的相关代码,并在两个编译器中运行它,一个是 https://www.tutorialspoint.com/compile_c_online.php (GCC) 的在线 C 编译器,另一个是使用 Visual Studio 2019。 两者都有以下代码吐出负值:
dur = UMAX(0,4 - number_fuzzy(level / 10));
printf("Dur = %i\n",dur);
基本上,UMAX 用于防止计算中出现非负值。 我们将级别除以 10,然后使用模糊/随机函数将其随机更改为 -1/+0/+1。我们从 4 中减去这个值,如果该值小于零,我们使用 UMAX 返回 0。 但是对于 50 到 59 级,这有时会产生负值,如下所示。但我从未见过它对 60-69 产生负面影响。 我知道模糊随机是随机改变值,但 UMAX 守卫应该始终有效,而不仅仅是某些级别。
完整代码如下:
//==================================================================
//= SLAP ME ON https://www.tutorialspoint.com/compile_c_online.PHP =
//==================================================================
#include <stdio.h>
#include<time.h> // pd 5
#define UMAX(a,b) ((a) > (b) ? (a) : (b))
#define OLD_RAND true
static int rgiState[2+55];
// Replacement
//https://p2p.wrox.com/c-programming/37911-my-coin-flip-game.html
void init_mm()
{
int *piState;
int iState;
piState = &rgiState[2];
piState[-2] = 55 - 55;
piState[-1] = 55 - 24;
piState[0] = ((int) time(NULL))&((1 << 30)- 1);
piState[1] = 1;
for(iState = 2; iState < 55; iState++)
{
piState[iState] = (piState[iState - 1] + piState[iState - 2])
& ((1 << 30)- 1);
}
return;
}
long number_mm( void )
{
#if defined (OLD_RAND)
int *piState;
int iState1,iState2,iRand;
piState = &rgiState[2];
iState1 = piState[-2];
iState2 = piState[-1];
iRand = (piState[iState1] + piState[iState2]) & ((1 << 30) - 1);
piState[iState1] = iRand;
if ( ++iState1 == 55 )
iState1 = 0;
if ( ++iState2 == 55 )
iState2 = 0;
piState[-2] = iState1;
piState[-1] = iState2;
return iRand >> 6;
#else
//return random() >> 6;
#endif
}
// db.c line 6267
int number_bits( int width )
{
return number_mm( ) & ( ( 1 << width ) - 1 );
}
// db.c line 6195
/* Stick a little fuzz on a number. */
int number_fuzzy( int number )
{
switch ( number_bits( 2 ) )
{
case 0: number -= 1; break;
case 3: number += 1; break;
}
return UMAX( 1,number );
}
int lixo(int a){
return UMAX( 1,a );
}
int main()
{
init_mm(); // Needed cause I guess this is for seeding for random number generation
int level = 50;
int dur = 0;
dur = UMAX(0,dur);
dur = UMAX(0,dur);
int test = 0;
test = UMAX(0,4 - lixo(level / 10));
printf("Test = %i\n",test);
}
可以返回/打印以下内容:
Dur = 0
Dur = 0
Dur = 0
Dur = -1
Dur = 0
Dur = -1
Dur = 0
Test = 0
使用 Visual Studio 2019,我继续组装,如下所示:
dur = UMAX(0,4 - number_fuzzy(level / 10));
00971A89 mov eax,dword ptr [level]
00971A8C cdq
00971A8D mov ecx,0Ah
00971A92 idiv eax,ecx
00971A94 push eax
00971A95 call _number_fuzzy (0971181h)
00971A9A add esp,4
00971A9D mov edx,4
00971AA2 sub edx,eax
00971AA4 jns main+72h (0971AB2h)
00971AA6 mov dword ptr [ebp-100h],0
00971AB0 jmp main+93h (0971AD3h)
00971AB2 mov eax,dword ptr [level]
00971AB5 cdq
00971AB6 mov ecx,0Ah
00971ABB idiv eax,ecx
00971ABD push eax
00971ABE call _number_fuzzy (0971181h)
00971AC3 add esp,4
00971AC6 mov edx,4
00971ACB sub edx,eax
00971ACD mov dword ptr [ebp-100h],edx
00971AD3 mov eax,dword ptr [ebp-100h]
00971AD9 mov dword ptr [dur],eax
printf("Dur = %i\n",dur);
00971ADC mov eax,dword ptr [dur]
00971ADF push eax
00971AE0 push offset string "Dur = %i\n" (0977B30h)
00971AE5 call _printf (09710D2h)
00971AEA add esp,8
dur = UMAX(0,4 - number_fuzzy(level / 10));
但是找不到原因。这很可能是因为我的组装技能不高。
一位朋友建议这可能与无符号整数有关。 但是我对 Lixo 函数进行了编码,它不会产生负面影响。 我知道这个错误很容易通过用 IF 替换 UMAX 来纠正,但由于技术上的好奇,我对这个错误非常感兴趣。此外,这个古老的 MUD 代码充满了 UMAX 调用,因此了解为什么会发生这种情况很重要。
那么有比我更精通 C 语言的人可以解释为什么会发生这种行为吗?
解决方法
您已经发现了类函数宏的众多问题之一。凭借其简单的文本替换功能,代码:
#define UMAX(a,b) ((a) > (b) ? (a) : (b))
dur = UMAX(0,4 - number_fuzzy(level / 10));
最终会变成:
dur = ((0) > (4 - number_fuzzy(level / 10))) ? (0) : (4 - number_fuzzy(level / 10)));
如果 number_fuzzy()
在使用相同参数调用时可以返回不同的值,那不会像您期望的那样工作。
如果你必须用宏(a)来做,你可以使用类似下面的东西,它只对每个参数求值一次:
#define UMAX_ASSIGN(var,val1,val2) { \
int var1 = val1; \
int var2 = val2; \
var = var1 > var2 ? var1 : var2; \
}
UMAX_ASSIGN(dur,4 - number_fuzzy(level / 10));
(a) 一个可疑的命题。你可能应该让它成为一个函数,让宏只用于非函数类的东西。
类似函数的宏在 C 的早期非常方便,当时编译器相对笨拙,计算机相对较慢。如今,它们的优势要少得多。
这样的事情应该是一个好的开始:
int UMax(int a,int b) { // use inline suggestion if desired.
if (a > b) return a;
return b;
}
,
你有这个代码:
#define UMAX(a,4 - number_fuzzy(level / 10));
相当于:
fuzz1 = 4 - number_fuzzy(level / 10);
fuzz2 = 4 - number_fuzzy(level / 10);
dur = 0 > fuzz1 ? 0 : fuzz2;
问题在于 fuzz1
和 fuzz2
不一样,因为它们是使用随机性生成的。
一个简单的修复:
fuzz1 = 4 - number_fuzzy(level / 10);
dur = UMAX(0,fuzz1);
这当然更有效,也更正确。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。