Search code examples
cbooleanmemcpyvoid-pointers

memcpy boolean to void *


I was just creating a testing function in which i have to pass boolean in void * so that i can parse it in other function and use it.

but i am stuck and not able to know that how should i memcpy the boolean in void *.

but when i am parsing it in another fucntion i am always getting the value true.

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

typedef struct {
    int a;
    uint8_t var_data[];
} s;

void parse(s * dummy)
{
    void *var_data = dummy->var_data;
    
    uint8_t *len;
    char type[128];
    bool *leaf;
    for(int i = 0; i < dummy->a; i++)
    {
        len = (uint8_t *)var_data;
        var_data += 1;
        memcpy(type, var_data, *len);
        type[*len] = '\0';
        var_data += *len;
        leaf = (bool *)var_data;
        var_data += 1;
        
        printf("%s\n", type);
        printf("leaf: %s\n\n", leaf ? "true" : "false");
    }
}

int main() 
{
    // Write C code here
    char val[] = "dummy value";
    uint8_t len = strlen(val);
    bool v = false;
    int b = 2;
    int sz = sizeof(s) + b * (sizeof(bool) + len + 1);
    s * dummy = (s *) malloc(sz);
    dummy->a = b;
    void *var = dummy->var_data;
    for(int i = 0; i < dummy->a; i++){
        memcpy(var, &len, 1);
        var += 1;
        memcpy(var, val, len);
        var += len;
        memcpy(var, &v, sizeof(bool));
        var += sizeof(bool);
    }
    parse(dummy);
    return 0;
}

can body help me with this problem.


Solution

  • You didn't dereference leaf in this line:

    printf("leaf: %s\n\n", leaf ? "true" : "false");
    

    Since leaf is a non-zero pointer, it will always evaluate to true in C. You want to print *leaf instead:

    printf("leaf: %s\n\n", *leaf ? "true" : "false");
    

    Some other misc remarks:

    1. void* arithmetic (i.e. var_data += 1) is illegal in C, although gcc will not complain. Use a char* because this is the type that's supposed to be used for serialization.

    2. As mentioned in other answers, using pointers like you are doing right now can lead to subtle errors. If your pointer is pointing to an address and you want to dereference it (read the value stored there), it's better to do this sooner than risk this location being changed by some other code in the meantime.

      So, just copy the data from the char* array into the target struct (or a primitive like uint8_t) and then advance the pointer.

    3. The only way you are technically allowed to cast pointers in C is to cast them from a specific pointer (like something*) to a char*, in order to inspect their contents. You can also implicitly cast from and to void*, but only if you are not aliasing the pointer (trying to modify the underlying type). Any casting in the other direction is a violation of strict aliasing, so you should try to use memcpy instead. It may look uglier, but compiler will optimize it anyway (see for yourself) and you'll be safe(r) from the horrors of aliasing.

    4. One nice habit to have it to try to utilize const-correctness wherever you can, it helps the compiler warn you if you're doing something wrong. If your function is parsing the array, the parameter should be const char*.

    5. Finally, if your goal is to serialize and deserialize structs, perhaps you should look into protocol buffers or some similar serialization framework. It is fast, efficient, portable and, best of all, already written.

    So, something like:

    typedef struct {
        int len;  
        char * var_data;
    } example;
    
    // note the const keyword - this means this function is
    // not going to change the struct, only read it
    void parse(const example * dummy)
    {
        // again, pointer to const char
        const char * var_data = dummy->var_data;
        
        // move all variables to the innermost scope
        for (int i = 0; i < dummy->len; i++)
        {
            uint8_t len = 0;
            memcpy(&len, var_data, sizeof(len));
            var_data++;
    
            ...
        }
    }