On my machine at work (Windows Vista, MinGW gcc 4.3.2) your code didn't produce any assembler for the asserts at any optimization level!
To get the asserts to be generated I had to come up with a volatile int
variable and compile with -O0
flag.
int main(void) {
float input[MAX_INPUTS] __attribute__ ((__aligned__(16)));
static float input_static[MAX_INPUTS] __attribute__ ((__aligned__(16)));
volatile int addr_as_int;
printf("Address of input: %p\n", &input);
addr_as_int = (int)input;
print_pointer(input);
print_int(addr_as_int);
printf("normal int: %08x; int%%16: %02x\n", addr_as_int, addr_as_int%16);
printf("Assert: %d\n", (addr_as_int % 16) == 0);
assert((addr_as_int % 16) == 0); /* Passes */
printf("Address of input_static: %p\n", &input_static);
addr_as_int = (int)input_static;
print_pointer(input_static);
print_int(addr_as_int);
printf("static int: %08x; int%%16: %02x\n", addr_as_int, (addr_as_int)%16);
printf("Assert: %d\n", (addr_as_int % 16) == 0);
assert((addr_as_int % 16) == 0); /* Does not Pass */
return 0;
}
I have no idea why the compiler chose to remove the asserts from the object file. I quick google search didn't reveal anything interesting.
Update 1 (added by @Pax at suggestion of @Falaina - we all suggest you accept this one if it turns out to be the case):
Actually I think @Falaina has nailed it in a comment to @Pax's answer:
Just a suggestions. Are you compiling with optimizations? It's possible the compiler is trying to be clever and going "Hey, this variable is aligned to 16 bytes, obviously the address % 16 is 0" and replacing all your checks with 1. Just a thought.
Here's the explanation. GCC is figuring out from the source code that input is indeed (supposed to be) aligned to 16 bytes. It's smart enough to the drop the assert
s altogether and to just print out 1 for the printf
s.
However, at the link stage, the linker is not able to guarantee alignment to 16 bytes, instead opting for 8 because (from @Pax):
Note that the effectiveness of aligned attributes may be limited by inherent limitations in your linker. On many systems, the linker is only able to arrange for variables to be aligned up to a certain maximum alignment. (For some linkers, the maximum supported alignment may be very very small.) If your linker is only able to align variables up to a maximum of 8 byte alignment, then specifying aligned(16) in an __attribute__ will still only provide you with 8 byte alignment. See your linker documentation for further information.
By then it's too late to get the assert
s and non-optimized printf
s back into the code. So the actual executable will not assert (since they've been taken out) and it will print the optimized 1 rather than calculating it an runtime.
The reason the volatile
fixes it in my answer is because GCC will not optimize the expressions that contain volatile components. It leaves the assert
s in and calculates the printf
arguments at runtime properly.
You can manually align your array if you don't mind declaring it a little bit larger than stricly necessary:
#include <assert.h>
#include <stdio.h>
#define MAX_INPUTS 250
void *force_align(void *base, size_t s, int align) {
size_t x;
int k = 0;
x = (size_t)base;
while ((k < align / (int)s) && (x % align)) {
k++;
x += s;
}
if (k == align) return NULL;
#if 0
printf("%d elements 'discarded'\n", k);
#endif
return (void*)((size_t)base + k*s);
}
int main(void) {
#define ALIGNMENT_REQ 16
#define EXTRA_ALIGN_REQ (ALIGNMENT_REQ / sizeof (float))
static float misaligned_input[MAX_INPUTS + EXTRA_ALIGN_REQ]
__attribute__ ((__aligned__(ALIGNMENT_REQ)));
float *input;
/* manual alignment, check for NULL */
assert( (input = force_align(misaligned_input, sizeof *input, ALIGNMENT_REQ)) );
printf("Address of misaligned input: %p\n", misaligned_input);
printf("Address of input: %p\n", input);
printf("Assert1: %x\n", ( ((int) (input)) ) );
printf("Assert2: %x\n", ( ((int) (input)) % ALIGNMENT_REQ ) );
printf("Assert3: %x\n", ( ((int) (input)) % ALIGNMENT_REQ ) == 0 );
assert ( ( ((int) (input)) ) );
#if 0
assert ( ( ((int) (input)) % ALIGNMENT_REQ ) ); /* Fails */
#endif
assert ( ( ((int) (input)) % ALIGNMENT_REQ ) == 0 ); /* Passes */
return 0;
}