Error collecting dynamic typing value

Asked

Viewed 51 times

1

I’m having trouble collecting the values in a dynamic C typing.

The inserted values as char, const char *, int, void * and long int work perfectly when placed in the printf (prints the value without passing the union), but when I use data like float and double the value returned is always 0, only works if you pass the full path of the union.

var. c:

#include <var.h>

const char *__var_type_2_string(var v){
    switch (v.type){
        case CHAR:
            return "Char";
        case INTEGER:
            return "Int";
        case L_INTEGER:
            return "Long Int";
        case FLOAT:
            return "Float";
        case DOUBLE:
            return "Double";
        case STRING:
            return "String";
        case POINTER:
            return "Pointer";
    }

    return "Undefined";
}

var. h:

#ifndef  __VAR_H__
#define  __VAR_H__

#define typeof(var) _Generic( (var),\
char: CHAR,\
int: INTEGER,\
long int: L_INTEGER,\
char *: STRING,\
const char *: STRING,\
void *: POINTER,\
float: FLOAT,\
double: DOUBLE,\
default: 0)

#define set_wtype(var, out) _Generic( (var),\
char: (out.data.c = var),\
int: (out.data.i = var),\
long int: (out.data.l = var),\
char *: (out.data.s = var),\
const char *: (out.data.s = var),\
void *: (out.data.p = var),\
default: 0)

#define set_wtypef(var, out) _Generic( (var),\
float: (out.data.f = var),\
double: (out.data.d = var),\
default: 0)

enum VAR_TYPE{
    CHAR        = 1,
    INTEGER     = 2,
    L_INTEGER   = 3,
    FLOAT       = 4,
    DOUBLE      = 5,
    STRING      = 6,
    POINTER     = 7
};

typedef struct __attribute__((__packed__)) _var{
    union _data{
        char c;
        int i;
        long int l;
        float f;
        double d;
        const char *s;
        void *p;
    } data;
    enum VAR_TYPE type;
}var;

const char *__var_type_2_string(var v);

#define var_set(var, dta)\
    var.type = typeof(dta);\
    set_wtype(dta, var)
#define var_setf(var, dta)\
    var.type = typeof(dta);\
    set_wtypef(dta, var)
//#define var_get(var) var.data
#define var_type(var) var.type
#define var_typeS(var) __var_type_2_string(var)

#endif  /*VAR_H*/

main. c:

#include <var.h>
#include <stdio.h>

int main(int argc, const char **argv){
    /*Array*/

    var vec[5];
    var_set(vec[0], 37);
    var_set(vec[1], 6625L);
    var_set(vec[2], "Text");
    var_set(vec[3], (char)'A');
    var_setf(vec[4], 13.33f);

    for(int x=0; x<5; x++){
        puts(var_typeS(vec[x]));
    }

    puts("\nResultados: ");
    printf("vec[0]= %i\n", vec[0]);
    printf("vec[1]= %li\n", vec[1]);
    printf("vec[2]= %s\n", vec[2]);
    printf("vec[3]= %c\n", vec[3]);
    printf("vec[4]= %f\n", vec[4]);
    printf("vec[4]= %f\n", vec[4].data.f);

    return 0;
}

Is there any way to be printing the value of vec[4] without passing vec[4].data.f in the printf?

exit:

Int
Long Int
String
Char
Float

Resultados: 
vec[0]= 37
vec[1]= 6625
vec[2]= Text
vec[3]= A
vec[4]= 0.000000
vec[4]= 13.330000

compilado em gcc-v6.3

1 answer

0

Call on printf thus, passing directly to struct var as an argument (vec[0], vec[1], etc) is not good practice because it can lead to Undefined behaviour.

Including, compiling the code as it is currently with the flag -Wall it is possible to observe a number of warnings.

So I would say that a more appropriate solution is to create a function __var_value_2_string(), similar to the __var_type_2_string, but to accomplish the conversion of all values (instead of guys) for char *.

A possible implementation of this function is as follows:

void __var_value_2_string(var v, char **out)
{
    char *s = NULL;
    char *default_str = "undefined";

    switch (v.type) {
        case CHAR:
            s = malloc(2 * sizeof(char));
            s[0] = v.data.c;
            s[1] = '\0';
            break;
        case INTEGER:
            s = malloc(21 * sizeof(char));
            snprintf(s, 21, "%i", v.data.i);
            break;
        case L_INTEGER:
            s = malloc(21 * sizeof(char));
            snprintf(s, 21, "%li", v.data.l);
            break;
        case FLOAT:
            s = malloc(21 * sizeof(char));
            snprintf(s, 21, "%f", v.data.f);
            break;
        case DOUBLE:
            s = malloc(21 * sizeof(char));
            snprintf(s, 21, "%lf", v.data.d);
            break;
        case STRING:
            s = malloc((strlen(v.data.s) + 1) * sizeof(char));
            strcpy(s, v.data.s);
            break;
        case POINTER:
            s = malloc(19 * sizeof(char));
            snprintf(s, 19, "0x%p", v.data.p);
            break;
        default:
            s = malloc((strlen(default_str) + 1) * sizeof(char));
            strcpy(s, default_str);
    }

    (*out) = s;
}

So you could add in var.h a new typedef:

#define var_valueS(var, out) __var_value_2_string(var, out)

And finally, in the main(), results could be displayed by making:

char *buffers[5];
for (int i = 0; i < 5; i++)
    var_valueS(vec[i], &buffers[i]);

puts("\nResultados: ");
for (int i = 0; i < 5; i++)
    printf("vec[%d] = %s\n", i, buffers[i]);

To conclude, it is important to realize that the buffers are being allocated via malloc() and, where appropriate, the memory associated with these buffers shall be released through the function free().

  • I thought I would do it this way, but I wanted something more dynamic, so Enum is in the first position, so when passing the variable to the printf, already have the value registered in the first bytes of struct. What I really needed was a solution to the printf launch the values float.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.