cfor-loopwhile-looplogical-operatorsrelational-operators

Relational Operators Will Not Function Properly In C


#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\t\t%+05d\n",0);
    printf("instructionCounter\t%02d\n",0);
    printf("instructionRegister\t%+05d\n",0);
    printf("operationCode\t\t%02d\n",0);
    printf("operand\t\t\t%02d\n",0);
    puts("");


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

    for(int i = 0; i<91; i+=10)
    {
      printf("%d\t",i);
      for(int j = 0; j < 10; j ++)
      {
          printf("%+.04d\t",*(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("");
}

In the function labeled "execute" under the arithmetic operation subtract I attempt to perform a logical comparison between two relational operators. *accumulator - memory[*operand] < -9999 || *accumulator - memory[*operand] > 9999. The purpose of this comparison is to check if the calculation resulted in a total that is outside the bounds of memory. When I tested conditions that should have resulted in a logical 0 (false) I only got a logical 1 (True). The program works flawlessly when the subtraction operation results in a positive number. However, when a negative number is encountered, the program terminates when it should not. Does anyone know what is wrong with the logical operation? PS ( This program is the "Simpletron Compiler" challenge from the book titled "Programming in C").


Solution

  • Based on the declaration of execute, the argument accumulator has a type of unsigned int *. Therefore, when you dereference accumulator, the type is unsigned. When you mix unsigned and signed types in arithmetic operations, the result is treated as unsigned, thus *accumulator - memory[*operand] would become a huge positive number (larger than 9999) when it should be negative. This should be the reason that causes the condition to unexpectedly hold.

    Therefore, it is better to cast accumulator to signed int before comparing with memory[*operand] - 9999 and memory[*operand] + 9999.