I have follow wired code. It run failed with clang++, and worked with g++.
In aarch64, long long int
is 8 bytes
, and the struct S94
is 16 bytes
(why? Seem in x86-64 is 1 byte
).
I see https://en.cppreference.com/w/cpp/language/bit_field , but it hasn't this case.
I guess is a undefined behavior or implementation-defined, cause it's so wired, but not have evidence.
Anyone can explain this code?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
extern void *memset (void *__s, int __c, size_t __n);
typedef long long int Talllong __attribute__((aligned));
struct S94 {
Talllong: 0;
};
struct S94 s94;
void check94va(int z, ...) {
va_list ap;
va_start(ap, z);
struct S94 arg1 = va_arg(ap, struct S94);
long long int tmp = va_arg(ap, long long);
//printf("result = %lld\n", tmp);
if (tmp != 2LL) {
printf("Fails!!!!\n");
}
va_end(ap);
}
int main(void) {
memset(&s94, '\0', sizeof(s94));
//printf("sizeof(s94) = %ld\n", sizeof(s94));
check94va(1, s94, 2LL);
return 0;
}
Edited: I know it's a unconventional C++ code, not follow some practice rule. But what I'm concerned about is whether it meets the standard, and whether compiler guaranteed the result.
Having a field of size 0 means that this and next field would have a memory location of next allocation unit boundary. In C++ for platforms with strict aligment requiremnts that unit would be of size sizeof(Talllong)
(in C, afaik, it's undefined,might be sizeof(int)
because field slarger than unsigned int
aren't supported).
As a result the beginning of struct, field with zero 0 and the end of struct have to have 3 distinct addresses, aligned by 8 bytes because next adjacent instance of S94
struct should start at unique aligned address. That makes size of struct to be 16.
x86-64 doesn't have allocation unit alignment requrements. This makes two first addresses same and struct would have the minimum possible size of char
.
You should use portable C11's alignas
isntead of compiler specific C-ism to ensure alignment, __attribute__((aligned))
isn't strict.
/* usually aligment is NOT requred in this case and is an extension.
:0 does it automatically.
*/
typedef long long int Talllong /*alignas(long long int)*/;
struct alignas(64) S94 {
Talllong w11: 4;
/* Adding up to 8 bytes of fields here won't change size */
Talllong: 0;
/* Adding up to 8 bytes of fields here won't change size */
Talllong w21: 12;
Talllong w22: 3;
};
It's not defined what alignment attributes do to bit fields because they don't have unique memory location and you can't take address of them. Compiler may ignore these attributes, display diagnostics or perform an "intuitively" natural change.
Note: order and position of bitfields within a single memory location is not reguated by standard, it's typically defined by platform and compiler. One of common changes is that little-endian and big-endian platforms order fields in opposing directions.