Thread: Generic Variable

  1. #1
    Registered User
    Join Date
    Dec 2012
    Posts
    61

    Generic Variable

    Hi! I'm trying to implementing shunting yard algorithm and I'm done converting it to postfix. I have some problem on evaluating it.

    Here's my code:

    Code:
    Tree* evaluateExpr(Tree** right, Tree** oper, Tree** left) {    
        Tree* result = NULL;
        
        char* rightType = (*right) -> type;
        char* leftType = (*left) -> type;
    
    
        char* type = !strcmp("float_typ", rightType) || !strcmp("float_typ", leftType) ? "float_typ" : "int_typ";
        void *rightVal, *leftVal, *value;
    
    
        if(!strcmp("int_typ", rightType)) {
            rightVal = (int*)malloc(sizeof(int));
            rightVal = atoi((*right) -> value);
        }
        else if(!strcmp("float_typ", rightType)) {
            rightVal = (float*)malloc(sizeof(float));
            rightVal = atof((*right) -> value);
        }
        
        if(!strcmp("int_typ", leftType)) {
            leftVal = (int*)malloc(sizeof(int));
            leftVal = atoi((*left) -> value);
        }
        else if(!strcmp("float_typ", leftType)) {
            leftVal = (float*)malloc(sizeof(float));
            leftVal = atof((*left) -> value);
        }
    
    
        value = strcmp("float_typ", type) ? (int*)malloc(sizeof(int)) : (float*)malloc(sizeof(float));
        
        if(!strcmp("+", (*oper) -> value))
            value = rightVal + leftVal;
    
    
        else if(!strcmp("-", (*oper) -> value))
            value = rightVal - leftVal;
    
    
        else if(!strcmp("*", (*oper) -> value))
            value = rightVal * leftVal;
    
    
        else if(!strcmp("%", (*oper) -> value)) 
            value = rightVal % leftVal;
    
    
        else if(!strcmp("/", (*oper) -> value))
            value = rightVal / leftVal;
    
    
        result = newNode(type, 0, (*oper) -> line);
        result -> type = type;
        result -> value = convertToChar(value, type);
    
    
        return result;
    }
    Based on the code above I'm trying to use a generic function to evaluate it and I got some error:

    Code:
    include/rules.c: In function ‘evaluateExpr’:include/rules.c:241:12: warning: assignment makes pointer from integer without a cast [enabled by default]
       rightVal = atoi((*right) -> value);
                ^
    include/rules.c:245:12: error: incompatible types when assigning to type ‘void *’ from type ‘double’
       rightVal = atof((*right) -> value);
                ^
    include/rules.c:250:11: warning: assignment makes pointer from integer without a cast [enabled by default]
       leftVal = atoi((*left) -> value);
               ^
    include/rules.c:254:11: error: incompatible types when assigning to type ‘void *’ from type ‘double’
       leftVal = atof((*left) -> value);
               ^
    include/rules.c:257:64: warning: pointer type mismatch in conditional expression [enabled by default]
      value = strcmp("float_typ", type) ? (int*)malloc(sizeof(int)) : (float*)malloc(sizeof(float));
                                                                    ^
    include/rules.c:260:20: error: invalid operands to binary + (have ‘void *’ and ‘void *’)
       value = rightVal + leftVal;
                        ^
    include/rules.c:263:9: warning: assignment makes pointer from integer without a cast [enabled by default]
       value = rightVal - leftVal;
             ^
    include/rules.c:266:20: error: invalid operands to binary * (have ‘void *’ and ‘void *’)
       value = rightVal * leftVal;
                        ^
    include/rules.c:269:20: error: invalid operands to binary % (have ‘void *’ and ‘void *’)
       value = rightVal % leftVal;
                        ^
    include/rules.c:272:20: error: invalid operands to binary / (have ‘void *’ and ‘void *’)
       value = rightVal / leftVal;
    Hope you can help me with this, Thanks

  2. #2
    Registered User
    Join Date
    May 2013
    Posts
    228
    Well, I'm far from being expert, but it seems like the compiler is saying exactly what's wrong:

    Code:
    rightVal = atoi((*right) -> value);
    Although this only raises a warning, but it's one you don't want to ignore. It is unclear why you'd want to assign a void* with the return value of of atoi(), as it seems like 'value' represents a pointer to a string representing a numeric value.

    Code:
    rightVal = atof((*right) -> value);
    While the previous statement only raised a warning, this is an error, since unlike before, the compiler can't make sense from a float-to-address conversion.

    Code:
    value = strcmp("float_typ", type) ? (int*)malloc(sizeof(int)) : (float*)malloc(sizeof(float));
    This also confuses the compiler, because if the condition is true (not zero), then the expression evaluates to int*, but if it is false, it evaluates to float*.
    I guess you can't have two different types in the "then" and "else" branch, hence the warning.

    The rest of the errors caused by your attempt to make binary operations between void*'s.
    I'm not sure, but I think that most of the compilers (if not all) won't allow an arithmetic operations on a void*. You have to cast it first to a specific type.
    Last edited by Absurd; 09-23-2014 at 02:54 PM.

  3. #3
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    C doesn't let you convert between pointers and integers at-will, without something like a typecast. The reason is that a pointer and an integer may not be the same size, or may not be compatible in some other way. You can force it by using a typecast, but that is almost always the wrong solution, and definitely would be in your case. And because you're "forcing" it, it might not work properly.

    One solution is that you use a union type containing an int, double and whatever other types you wish to support. Instead of a void * field for value, you have the union type. Assign to and read from the correct type for each operand, based on the type flag

    If you insist on using void *, the right solution would be to malloc an int/double/etc for each number. The pointer returned by malloc (remember to check for NULL though, malloc has been known to fail) is what you insert into the expression tree, and the location pointed to is where you store your value:
    Code:
    if I read an int
        int *value = malloc(sizeof(*value));
        if value NULL
            handle malloc failure
        else
            *value = the number I read
            insert value into tree
    Then, when you remove an entry when you are evaluating the expression, you check the type of the item, and convert it properly before using it in an expression. This method would also benefit from using a union type with all the supported types in it.

    One more note, I would use an enum instead of strings to represent the type of an operand. The compiler can more easily check you're only using correct values, and it make the code easier to read (compare using == instead of strcmp, for example). If you like strings because it makes debugging output clear, consider a small function that converts the enum value to a string using a simple case statement. If you still really want to use strings, consider defining constants that represent the values. That allows for easier maintenance and better checking that you're using the right string values. You want to avoid having to debug your code because in some places you did "float_typ" and in others "float_type".

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Structure variable : how to set as generic ?
    By pprabhakar in forum C Programming
    Replies: 3
    Last Post: 07-06-2006, 08:04 AM