You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言关系运算符异常:Simpletron减法越界判断错误排查

Simpletron模拟器减法溢出判断逻辑问题排查

这是《Programming in C》一书中的Simpletron模拟器实现代码。在execute函数的SUBTRACT算术操作模块中,通过表达式*accumulator - memory[*operand] < -9999 || *accumulator - memory[*operand] > 9999判断减法计算结果是否超出[-9999, 9999]的内存范围。测试发现,当结果为正数时程序运行正常,但结果为负数时,本该返回false的判断却返回true,导致程序异常终止。

问题代码

#include <stdio.h>
#include <stdlib.h>

// Input/Output Operations:
#define READ 10
#define WRITE 11

// Load/Store Operations:
#define LOAD 20
#define STORE 21

// Arithmetic Operations:
#define ADD 30
#define SUBTRACT 31
#define DIVIDE 32
#define MULTIPLY 33

//Transfer-of-control Operations:
#define BRANCH 40
#define BRANCHNEG 41
#define BRANCHZERO 42
#define HALT 43

void main_message();
void load(int *memory,int *instructionCounter);
void execute(int *instructionCounter, int memory[], int *instructionRegister, int *operationCode, int *operand, unsigned int *accumulator);
void dump(int *memory);

int main()
{
    main_message();

    //Special Registers
    int memory[101] = {+0000};
    unsigned int accumulator = 0000;
    int instructionCounter = 00;
    unsigned int instructionRegister = 0000;
    int operationCode = 00;
    int operand = 00;


    load(memory,&instructionCounter);
    execute(&instructionCounter, memory, &instructionRegister, &operationCode, &operand, &accumulator);
    computer_dump(memory);
    return 0;
}
void main_message()
{
    puts("*** Welcome to Simpletron! ***");
    puts("*** Please enter your program one instruction ***");
    puts("*** (or data word) at a time. I will type the ***");
    puts("*** location number and a question mark (?).  ***");
    puts("*** You then type the word for that location. ***");
    puts("*** Type the sentinel -99999 to stop entering ***");
    puts("*** your program. ***");
    puts("");
    puts("");
}
void computer_dump(int *memory)
{
    //Special Computer Registers
    puts("REGISTERS:");
    printf("accumulator		%+05d\n",0);
    printf("instructionCounter	%02d\n",0);
    printf("instructionRegister	%+05d\n",0);
    printf("operationCode		%02d\n",0);
    printf("operand			%02d\n",0);
    puts("");


    //Printing Memory
    puts("MEMORY:");
    for(int i = 0; i<10; i++)
        printf("	%d",i);
    puts("");

    for(int i = 0; i<91; i+=10)
    {
      printf("%d	",i);
      for(int j = 0; j < 10; j ++)
      {
          printf("%+.04d	",*(memory + (i+j)));
      }
      puts("");
    }
}
void load(int *memory,int *instructionCounter)
{
    //Goal load data into memory array using pointers
    while(1)
    {
        printf("%02d ?  ", *instructionCounter);
        scanf("%d", (memory + *instructionCounter));

        if(*(memory + *instructionCounter) == -99999)                                             // Checking if termination value has been entered
        {
            *(memory + *instructionCounter) = 00;
            break;
        }

        if(*(memory + *instructionCounter) < -9999 || *(memory + *instructionCounter) > 9999)                       // Checking if word is in range
        {
            *(memory + *instructionCounter) = 00;
            puts("Please type a word between the ranges of -9999 and +9999");
            continue;
        }
        *instructionCounter+=1;
    };

    puts("*** Program loading completed ***");
    puts("*** Program execution begins  ***");
    puts("");
    puts("");
}
void execute(int *instructionCounter, int memory[], int *instructionRegister, int *operationCode, int *operand, unsigned int *accumulator)
{
    puts("Performing the execution phase!");
    for (int i = 0; i <*instructionCounter; i++)
    {
        *instructionRegister = memory[i];
        *operationCode = *instructionRegister / 100;
        *operand = *instructionRegister % 100;

        // operation instructions
        if(*operationCode == READ)          // Input/Output operations
        {
            printf("? ");
            scanf("%d", &memory[*operand]);
        }
        else if(*operationCode == WRITE)
        {
            printf("%d",memory[*operand]);
        }
        else if(*operationCode == LOAD)     // Load/Store Operations
        {
            *accumulator = memory[*operand];
        }
        else if(*operationCode == STORE)
        {
            memory[*operand] = *accumulator;
        }
        else if(*operationCode == ADD)     // Arithmetic Operations
        {
            if (*accumulator + memory[*operand] < -9999 || *accumulator + memory[*operand] > 9999 )
            {
                puts("*** Operation resulted in a value outside the bounds of memory ***");
                puts("*** Simpletron execution abnormally terminated ***");
                break;
            }
            *accumulator+= memory[*operand];
            printf("Accumulator after addition operation performed: %d\n",*accumulator);
        }
        else if(*operationCode == SUBTRACT)
        {
             if (*accumulator - memory[*operand] < -9999 || (*accumulator - memory[*operand]) > 9999 )
            {
                puts("*** Operation resulted in a value outside the bounds of memory ***");
                puts("*** Simpletron execution abnormally terminated ***");
                break;
            }
            *accumulator -= memory[*operand];
        }
        else if(*operationCode == DIVIDE)
        {
            if (memory[*operand] == 0)                                       // Checking to see if number is undefined 
            {
                puts("*** Attempt to divide by Zero ***");                  
                puts("*** Simpletron execution abnormally terminated  ***");
                break;
            }
            *accumulator = *accumulator / memory[*operand];
        }
        else if(*operationCode == MULTIPLY)
        {
             if (*accumulator * memory[*operand] < -9999 || *accumulator * memory[*operand] > 9999 )
            {
                puts("*** Operation resulted in a value outside the bounds of memory ***");
                puts("*** Simpletron execution abnormally terminated ***");
                break;
            }
            *accumulator = *accumulator * memory[*operand];
        }
        else if(*operationCode == BRANCH)     // Transfer-Of-Control Operations
        {
            i = *operand;
        }
        else if(*operationCode == BRANCHNEG)
        {
            if(*accumulator < 0)
                i = *operand;
        }
        else if(*operationCode == BRANCHZERO)
        {
            if(*accumulator == 0)
                i = *operand;
        }
        else if(*operationCode == HALT)
        {
            puts("*** Simpletron execution terminated ***");
        }
    }
    puts("");
    puts("");
}

问题原因

核心错误在于accumulator被定义为无符号整数(unsigned int),而Simpletron的累加器需要支持正负数值运算。当无符号整数参与减法运算得到负数结果时,会触发无符号整数溢出回绕:比如0 - 1在32位系统中会被计算为4294967295(无符号的最大值)。

此时进行范围判断时,这个超大的无符号数会被隐式转换为有符号整数(或者按无符号规则比较),导致*accumulator - memory[*operand] > 9999的判断成立,错误触发异常终止逻辑。

另外,BRANCHNEG分支中的if(*accumulator < 0)判断也完全无效——无符号整数永远不可能小于0,这同样是类型定义错误导致的逻辑问题。

修复方案

  1. 修改accumulator的类型为有符号整数(推荐):
    将unsigned int accumulator = 0000;改为int accumulator = 0;,同时调整函数参数中的类型声明,确保所有相关变量都使用有符号类型。这是最彻底的修复,符合Simpletron累加器的设计需求。

  2. 临时转换为有符号类型计算(临时方案):
    如果暂时不想修改类型,可以在减法运算前将无符号值转换为有符号整数计算,再判断范围:

    else if(*operationCode == SUBTRACT)
    {
         int temp_result = (int)*accumulator - memory[*operand];
         if (temp_result < -9999 || temp_result > 9999 )
         {
             puts("*** Operation resulted in a value outside the bounds of memory ***");
             puts("*** Simpletron execution abnormally terminated ***");
             break;
         }
         *accumulator = (unsigned int)temp_result;
    }
    

    但这种方式需要额外处理类型转换的溢出风险,且无法解决BRANCHNEG等其他分支的逻辑错误,因此不推荐。

注意:其他算术操作(ADD、MULTIPLY)以及BRANCHNEG分支也存在相同的无符号类型问题,需要同步修复。

内容的提问来源于stack exchange,提问作者Austin Castro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 05:45:29