strtol in c not giving me consistent values. How does strtol work?

300 views Asked by At

I have written the following lexical analyzer. It works correctly for inputs like: c&3&f, (3|6)&c, f^1. However the results I am getting for strtol are not consistent. When I run <3|3 it converts hex 3 to decimal 8 for the first 3 value and then correctly converts it to 3 for the second value. This is my entire program. The problem is in the last function. I added printf's to debug my code. (Pass a text file through stdin < to run. New expression on each line)

Code can also be found at: Github

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

//Max number of characters on new line from file
#define LINE_MAX 1028

char expression[LINE_MAX];
int position;

char next();
char peek();
int E();
int EE(int i);
int A();
int AA(int i);
int B();
int BB(int i);
int C();

int main ( int argc, char *argv[] )
{
    char line[LINE_MAX];

    while (fgets(line, LINE_MAX, stdin) != NULL) {

        //remove the newline character for printing the expression
        size_t strlength = strlen(line);
        line[strlength-1] = '\0';

        //reset global variables
        position = 0;
        strcpy(expression, line);

        int result = E();

        printf("%s =  %x\n", line, result);
    }
}

char next(){
    return expression[position++];
}

char peek(){
    return expression[position];
}

int E(){
    int st = A();
    return EE(st);
}

//bitwise "|" OR
int EE(int i){
    char token = peek();

    if (token == '|'){ 
        next();
        int val = A();
        return EE(i | val);
    }else{
        return i; 
    }
}

int A(){
    int st = B();
    return AA(st);
}

//bitwise "^" XOR
int AA(int i){
    char token = peek();

    if (token == '^'){ 
        next();
        int val = B();
        return AA(i ^ val);
    }else{
        return i; 
    }
}

int B(){
    int st = C();
    return BB(st);
}

//bitwise "&" AND
int BB(int i){
    char token = peek();

    if (token == '&'){ 
        next();
        int val = C();
        return BB(i & val);
    }else{
        return i; 
    }
}

/*********************************************************************
 *********************************************************************
 This is the function I am having a problem with. Strtol is giving me 
 inconsistent integer values.
 *********************************************************************
 *********************************************************************/
int C(){ 

    char token = next(); 

    if(token == '<'){
        //bitwise shift secondToken <<
        printf("BITEWISE LEFT SHIFT: %c\n", token);
        return (C() << 1) & 15; //0xf;
    }else if(token == '>'){
        //bitwise shift secondToken >>
        return C() >> 1;
    }else if(token == '~'){
        //bitwise not secondToken ~
        printf("BITEWISE NOT: %c\n", token);
        return (~C()) & 15;
    }else if(token == '('){
        int val = E();
        next();
        return val; 
    }else{
        printf("TOKEN: %c\n", token);
        //return the token hex value as int
        char temp[1];
        temp[0] = token;
        printf("TEMP 0: %c\n", temp[0]);
        printf("TOKEN int: %d\n", (int)strtol(temp, NULL, 16) & 15);
        return (int)(strtol(temp, NULL, 16) & 15); //0xf;
    }
}

The results of running it for c&3&f and <3|3 are follows:

TOKEN: c
TEMP 0: c
TOKEN int: 12
TOKEN: 3
TEMP 0: 3
TOKEN int: 3
TOKEN: f
TEMP 0: f
TOKEN int: 15
c&3&f  =  0

BITEWISE LEFT SHIFT: <
TOKEN: 3
TEMP 0: 3
TOKEN int: 8
TOKEN: 3
TEMP 0: 3
TOKEN int: 3
<3|3  =  3

As you can see the first "TOKEN int" value for the second expression should be 3 but it is returning 8. Then it correctly converts the 3 to 3 after that. Does anyone know why this is happening? How does strtol convert to decimal?

1

There are 1 answers

0
paxdiablo On BEST ANSWER

Change:

char temp[1];
temp[0] = token;

into:

char temp[2];
temp[0] = token;
temp[1] = '\0';

(assuming you're only wanting to handle single-digit numbers).

When you're doing strtol() in the former case, it's expecting a C-style string and what you're giving is not guaranteed to be null-terminated.

So what's probably happening is that you're memory has something like 38q in it, strotol(temp,NULL,16) will turn that into 56 which will, when and-ed with 15, give you 8.