C:调试和发布模式的差异
c: difference in debug and release mode?
我试图建立一个简单的库整数操作没有绑定(我知道GMP的存在,只是为了我自己的利益)。我通过教计算机用字符数组做小学算术来做到这一点。我知道这是一种非常低效的方式,但这是我能想到的,也是我正在做的。我已经成功地为所有四个+-*/操作编写了C代码,但不知何故只能在调试模式下。代码在GDB和Visual Studio 2013调试模式下都能很好地工作;我已经测试得够多了。但是,在发布模式下的正常执行过程中,它会不断抛出错误。我已经搜索了很多关于在调试期间未检测到的发布模式问题的主题,但我发现的解决方案似乎不适合我的情况,至少在我可以看到的范围内。
edit:我所说的'error'是指我的代码将执行'goto error;',这意味着计算结果是混乱的,所以它没有通过main()中给出的随机整数计算测试。这种错误并不总是发生,而是在释放模式中大约10~20次成功操作后发生。
在调试期间不会出现单个(任何一般)错误。是我在代码中犯的一个非常简单的错误,一个简短的修复将使一切都很好吗?也许我的整个代码就是一团乱麻?是我的Windows 7系统有问题吗?或者其他可能的事情?我已尽我所能来处理这个问题,但现在我却无能为力。如有任何帮助,我将不胜感激。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define A_PLUS -1
#define A_MINUS -2
#define INT_LEN 10
typedef struct{
int sign;
int start;
char *num;
} abn;
void initABN(abn *n);
void sInitABN(abn *n, char *cs);
void iInitABN(abn *n, int num);
void sReInitABN(abn *n, char *cs);
void iReInitABN(abn *n, int num);
void delABN(abn *n);
int aBigger(const abn *king, const abn *slave);
void aPlus(abn *t, const abn *a, const abn *b);
void aMinus(abn *t, const abn *a, const abn *b);
void printABN(const abn *a);
int abnToInt(const abn *a);
int iPow(int base, int exp);
int fromElse = 0;
int main(){
srand((unsigned)time(NULL));
printf("number of tests for each operation: ");
int testN;
scanf("%d", &testN);
printf("n");
abn a, b;
initABN(&a); initABN(&b);
int i, t1, t2;
for (i = 0; i < testN; ++i){
t1 = rand()*(2*(rand() % 2) - 1);
t2 = rand()*(2*(rand() % 2) - 1);
iReInitABN(&a, t1);
iReInitABN(&b, t2);
printABN(&a);
printf(" + ");
printABN(&b);
printf(" = ");
aPlus(&a, &a, &b);
printABN(&a);
if (t1 + t2 == abnToInt(&a)){
printf(" TRUEn");
}else{
goto error;
}
}
for (i = 0; i < testN; ++i){
t1 = rand()*(2*(rand() % 2) - 1);
t2 = rand()*(2*(rand() % 2) - 1);
iReInitABN(&a, t1);
iReInitABN(&b, t2);
printABN(&a);
printf(" - ");
printABN(&b);
printf(" = ");
aMinus(&a, &a, &b);
printABN(&a);
if (t1 - t2 == abnToInt(&a)){
printf(" TRUEn");
}else{
goto error;
}
}
delABN(&a); delABN(&b);
printf("Test Complete!n");
return 0;
error:
printf("nERRORn");
system("pause");
return 1;
}
void initABN(abn *n){
n->num = NULL;
}
void sInitABN(abn *n, char *cs){
int i;
for (i = 0; cs[i] != 0; ++i); --i;
if (cs[0] == '-'){
n->sign = A_MINUS;
n->start = i - 1;
n->num = (char*)malloc(i);
for (; i > 0; --i){
n->num[n->start - i + 1] = cs[i] - '0';
}
}else{
n->sign = A_PLUS;
n->start = i;
n->num = (char*)malloc(i + 1);
for (; i >= 0; --i){
n->num[n->start - i] = cs[i] - '0';
}
}
}
void iInitABN(abn *n, int num){
char *tempCs = (char*)malloc(INT_LEN + 1);
sprintf(tempCs, "%d", num);
sInitABN(n, tempCs);
free(tempCs);
}
void sReInitABN(abn *n, char *cs){
free(n->num);
sInitABN(n, cs);
}
void iReInitABN(abn *n, int num){
char *tempCs = (char*)malloc(INT_LEN + 1);
sprintf(tempCs, "%d", num);
sReInitABN(n, tempCs);
free(tempCs);
}
void delABN(abn *n){
free(n->num);
n->num = NULL;
}
int aBigger(const abn *king, const abn *slave){
int kingSize = king->start, slaveSize = slave->start;
if (kingSize > slaveSize){
return 1;
}
if (kingSize < slaveSize){
return 0;
}
int i;
for (i = kingSize; i >= 0; --i){
if (king->num[i] > slave->num[i]){
return 1;
}
if (king->num[i] < slave->num[i]){
return 0;
}
}
return 0;
}
void aPlus(abn *t, const abn *a, const abn *b){
int aSign = a->sign, bSign = b->sign;
if (!fromElse){
if (aSign != bSign){
fromElse = 1;
aMinus(t, a, b);
fromElse = 0;
return;
}
}
char *temp;
int aStart = a->start, bStart = b->start;
if (aStart > bStart){
t->start = aStart + 1;
temp = (char*)calloc(aStart + 2, 1);
}else{
t->start = bStart + 1;
temp = (char*)calloc(bStart + 2, 1);
}
int i, j;
for (i = 0; i <= aStart; ++i){
temp[i] += a->num[i];
}
for (i = 0; i <= bStart; ++i){
temp[i] += b->num[i];
if (temp[i] >= 10){
temp[i] -= 10;
++temp[i + 1];
for (j = i + 1; ; ++j){
if (temp[j] >= 10){
temp[j] -= 10;
++temp[j + 1];
}else{
break;
}
}
}
}
if (temp[t->start] == 0){
--t->start;
}
if (aSign == A_PLUS){
t->sign = A_PLUS;
}else{
t->sign = A_MINUS;
}
free(t->num);
t->num = temp;
}
void aMinus(abn *t, const abn *a, const abn *b){
int aSign = a->sign, bSign = b->sign;
if (!fromElse){
if (aSign != bSign){
fromElse = 1;
aPlus(t, a, b);
fromElse = 0;
return;
}
}
char *temp;
int aStart = a->start, bStart = b->start;
if (aStart > bStart){
t->start = aStart;
temp = (char*)calloc(aStart + 1, 1);
}else{
t->start = bStart;
temp = (char*)calloc(bStart + 1, 1);
}
int i;
#define MIN_CALC(A, B)
for (i = 0; i <= A##Start; ++i){
temp[i] += A->num[i];
}
for (i = 0; i <= B##Start; ++i){
temp[i] -= B->num[i];
if (temp[i] < 0){
temp[i] += 10;
temp[i + 1] -= 1;
}
}
if (aBigger(a, b)){
MIN_CALC(a, b);
if (aSign == A_PLUS){
t->sign = A_PLUS;
}else{
t->sign = A_MINUS;
}
}else{
MIN_CALC(b, a);
if (aSign == A_PLUS){
t->sign = A_MINUS;
}else{
t->sign = A_PLUS;
}
}
for (i = t->start; i > 0; --i){
if (temp[i] == 0){
--t->start;
}else{
break;
}
}
free(t->num);
t->num = temp;
}
void printABN(const abn *a){
if (a->start == 0 && a->num[0] == 0){
printf("0");
return;
}
if (a->sign == A_MINUS){
printf("-");
}
int i;
for (i = a->start; i >= 0; --i){
printf("%d", a->num[i]);
}
}
int abnToInt(const abn *a){
int i, n = 0;
for (i = 0; i <= a->start; ++i){
n += a->num[i]*iPow(10, i);
}
if (a->sign == A_MINUS){
n *= -1;
}
return n;
}
int iPow(int base, int exp){
int n = 1;
int i;
for (i = 0; i < exp; ++i){
n *= base;
}
return n;
}
这是由于t
和a
指向相同的值。修改t
所指向的值,也会修改a
所指向的值。
在aMinus
函数中,在调用aBigger
时间接使用a->start
的值。但是,您已经在前面的函数中更改了t->start
和a->start
的值。
这里有三种解决这个问题的方法:
-
更改代码,以便对
t->start
的修改发生在函数的后面(将值保存到一个新的局部变量并在需要之前设置)修复该问题。我认为这是最好的办法。 -
更改
aBigger
函数以长度作为参数并使用aStart
和bstart
作为值,但仍然意味着您已经更改了a->start
,并且可能会忘记并更改代码以在将来使用a->start
。 -
更改调用,将加减法的结果放入不同的变量中。这是有效的,但它仍然意味着你的函数有潜在的漏洞。
我无法解释为什么它在调试模式下工作,或者在调试发布模式时,我将尝试逐步执行,看看是否可以进一步跟踪它。
- 为什么使用__LINE_的代码在发布模式下在MSVC下编译,而不是在调试模式下
- 小字符串优化(调试与发布模式)
- 在调试模式下引发C++ "deque iterator not dereferencable"异常
- _mm256_load_ps调试模式下导致谷歌/基准测试的分段错误
- Visual Studio 发布模式阻止在调试模式下执行的代码.使用 WinHTTP 和多线程
- 自定义内存管理器在发布模式下工作正常,但在调试模式下则不然
- 使用Qt Creator在调试模式下编译一段代码
- 在调试模式下,所有程序都运行良好,但在发布模式下,我在cudaMalloc操作中出错
- 在类声明中初始化 const 成员变量时在调试模式下出现异常
- 在调试模式下编译时qrc_resource.cpp错误
- 如何在调试模式下通过终端运行可执行的 c++?
- 在Visual Studio 2017上无法使用调试模式x64进行OpenCV3.2编译
- 在调试模式下使用英特尔 TBB
- 我的代码在发布模式下不起作用,而在Qt的调试模式下工作
- SCANF 在 Eclipse 中不接受调试模式下的输入?
- 为什么我的 UWP 游戏在发布时比在调试模式下慢
- 在发布模式下崩溃,但如果可调试为 true - 不是..什么是可能的问题
- Visual Studio混合模式调试是否可以附加到Jupyter笔记本以同时调试C++和Python
- Windows 用户模式调试器传输 Visual Studio 2012
- VS2010 中使用 .NET 3.5 的混合模式调试