2

Consider the following structs:

typedef struct {
 uint32_t foo;
 uint32_t bar;
} first_struct_t;
typedef struct {
 first_struct_t f;
 uint8_t *p;
 uint8_t buf[];
} second_struct_t;

However, later in my code, the following assignment happens:

typedef struct {
 first_struct_t *f;
 // ...
} some_struct;
int function_before_foo(some_struct *p) {
 p->f = (second_struct_t *) malloc(sizeof(second_struct_t));
 // ...
}
int function_foo(some_struct *p) {
 second_struct_t *s = (second_struct_t *) p->f;
 // ...
}

And it generates the following error due to -Wcast-align:

'second_struct_t *' increases required alignment from 4 to 8 [-Werror,-Wcast-align]
second_struct_t *s = (second_struct_t *) p->f;

A solution is to cast it to a void *, but that seems to only mask the problem. What is the cleanest solution to this?

EDIT: This only happens with clang and not GCC, regardless of the fact that both compilers are given the -Wcast-align flag.

asked Oct 19, 2015 at 15:55
4
  • some_struct *p and struct_second_t *s are not interchangeable (a pointer to a structure always point to its first member and this is not the case). Do you mean first_struct_t *s = (first_struct_t *) p->f;? Commented Oct 19, 2015 at 16:10
  • Isn't p->f a first_struct_t? Not a first_struct_t *? Commented Oct 19, 2015 at 16:24
  • You're correct. I fixed the invalid wording. Commented Oct 19, 2015 at 16:40
  • stackoverflow.com/questions/10951039/… Try forcing first_struct_t a 8 byte alignment. Commented Oct 19, 2015 at 17:57

1 Answer 1

1

I'm going to assume when you have struct_second_t you actually meant second_struct_t, otherwise your code does not compile.

The problem is that f in some_struct is a pointer to a first_struct_t not a pointer to a second_struct_t.

I should add that the cast in struct_second_t *s = (struct_second_t *) p->f; is hiding the warning message. In general if you have to cast one pointer to another you are more often than not going to cause undefined behavior. This is not always true but is a pretty good guideline.

In response to comment.

First it appears you will not get that warning with gcc for x86 (32 and 64 bit) as there is no alignment requirement for general purpose registers although alignment can improve performance (see this SO post for more info). As to why clang emits that warning, perhaps because of performance or they do not have the exception as gcc does for x86.

Second what you are trying to accomplish is similar to what the container_of macro does in the Linux kernel. container_of is typically defined as:

#define container_of(ptr, type, member) ({ \
 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
 (type *)( (char *)__mptr - offsetof(type,member) );})

In searching the only thing I have found that addresses your issue is this commit to tup that changed their version of container_of to include a cast to void*.

Basically, I believe the issue is while you know that p->f actually points to a second_struct_t your compiler does not and therefore issues the warning. So you can either not do that or cast to void*.

Additional:

It seems mozilla address the issue by casting to void* as well:

Finally, I would recommend looking at container_of and using that instead of relying on the fact that the first element of the struct is the other struct. This way your code is more resilient, if someone else changes the order of the struct members it will still work. You will have to add a void* cast to container_of to avoid the warning. Note that on architectures with alignment issues, you should not have an issue at runtime assuming you always do your type change between child and parent correctly.

answered Oct 19, 2015 at 16:32
Sign up to request clarification or add additional context in comments.

1 Comment

I'm using the ->f variable to store a pointer to an instance of second_struct_t. Basically it's a cheap way of doing polymorphism. You can use ->f to access first_struct_t and if you know about it, you can gain access to second_struct_t. In this case, I know about second_struct_t and am willing to cast it that way.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.