0

I'm using the macro container_of defined as:

#define container_of(ptr, type, member) ((type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member)))

the structure vector:

struct vector {
    uint32_t signature;
    size_t element_size;
    size_t size;
    void *data;
};

And finally the function vectorSize receiving a pointer to some data. This function is not working because only the data member inside struct vector v have the right value, the others have garbage, resulting in failing the if statement SIGNATURE.

size_t vectorSize(void *vec)
{
    void **pdata = &vec;
    struct vector *v = container_of(pdata, struct vector, data);

    if (v->signature != VECTOR_SIGNATURE) return 0;
    return v->size;
}

What is wrong with my setup?

Bungow
  • 420
  • 5
  • 11
  • I don't understand. If the container of the pointer is is not properly initialized, why do you blame the macro? – Eugene Sh. Mar 05 '18 at 19:05
  • @EugeneSh. The container is properly initialized. But when I retrieve it with container_of only data pointer is set correctly – Bungow Mar 05 '18 at 19:07
  • 2
    Because the `vec` parameter is not the member of a `vector` structure. It might be a copy of such a member but that doesn't help. – interjay Mar 05 '18 at 19:13
  • @interjay Good point. Hard to spot... The `pdata` has to be the *actual address of the member*. Currently it is the address of the `vec` argument instead. You might want to change the signature of the function to take the actual address. – Eugene Sh. Mar 05 '18 at 19:14
  • @interjay Thank you so much. I was writting a complete example. Thank you for save me time and sorry if I'm not clear in english. – Bungow Mar 05 '18 at 19:19
  • @interjay.: This is a nice point - and easy to overlook. Why don't you put it as an answer? If you have some time.(Ofc when the question crosses the limit of mcve) – user2736738 Mar 05 '18 at 19:29
  • 1
    I don't get your macro, why do you do `1 ? (ptr) : ...` what's the point in using the `?:` operator when the condition is true anyway? – Pablo Mar 05 '18 at 19:30
  • The macro is weird indeed. Here is the "standard" implementation of it: https://stackoverflow.com/questions/15832301/understanding-container-of-macro-in-the-linux-kernel – Eugene Sh. Mar 05 '18 at 19:34
  • The `container_of()` macro is used to retrieved the container of a pointer, given the pointer is a field of the container. You would use it like this: `void *arbitrary_data; struct vector *vec = container_of(arbitrary_data, struct vector, data);` Right now, you're trying to retrieve the container of your vector pointer, as a vector. Does your vector's data points to another vector? Also, retrievint the address of `void* vec` does not make any sense. It's already the address you need. – Jazzwave06 Mar 05 '18 at 19:59

3 Answers3

0

First of all, please don't post code like 1 ? this : that. I know, this is experimental code from you whilst digging into the problem. But it shouldn't posted here as it confuses us.

If I understood you right, your function receives a pointer to a struct member and you need a macro delivering the container struct. Try this:

#define CONTAINER_OF(MemberPtr, StrucType, MemberName) ((StrucType*)( (char*)(MemberPtr) - offsetof(StrucType, MemberName)))

Followed by:

size_t vectorSize(void *vec)
{
    struct vector *v = CONTAINER_OF(vec, struct vector, data);

    if (v->signature != VECTOR_SIGNATURE) return 0;
    return v->size;
}
user5329483
  • 1,260
  • 7
  • 11
0

Example usage of the container_of macro:

struct vector *vector_of(void* element) 
{
    return container_of(element, struct vector, data);
}

For your implementation, it seems to me it should look like this:

size_t vector_size(void *vec_ptr)
{
    struct vector *vec = v_ptr;
    return vec->signature != VECTOR_SIGNATURE ? 0 : vec->size;
}
Jazzwave06
  • 1,883
  • 1
  • 11
  • 19
0

Since data is of type (void *), vec needs to be of (void **). But you should not give the address of vec. Instead, just cast it as a (void **). Like below:

struct vector *v = container_of((void **)vec, struct vector, data);
  • I assumed that the container_of macro is same as the one defined in the linux kernel. In that case, you have to cast it to avoid the compile error. And you should just pass the value of `vec` itself to get the correct address of the `container`. – Eric Lee Nov 20 '18 at 10:06