#include <stdio.h>
void main(void)
{
char array[4] = {0, 1, 2, 3};
float *fpek;
int i;
for(i=0;i<4;i++)
{
fprintf(stderr,"i = %d ", i);
fpek = (float *)(&array[i]);
fprintf(stderr, "fpek = %lx ", (unsigned long) fpek);
*fpek = (float) i + 10;
fprintf(stderr, "*fpek = %.2f\n", *fpek);
}
}
$ cc alignment.c
$ a.out
i = 0 fpek = effff0fc *fpek = 10.00
i = 1 fpek = effff0fd Bus error
The code above was found in C programming practice material. I understand the statements per se but I don't really see what the author is trying to illustrate. Why is there a bus error?
Aligned or not, this is just plain wrong:
fpek = (float *)(&array[i]); // invalid for i>0, questionable for i==0
fprintf(stderr, "fpek = %lx ", (unsigned long) fpek);
*fpek = (float) i + 10;
Since array is at-best four chars wide, even if your system-float is 4 bytes you're immediately addressing (likely unaligned) data i bytes out of range of your array when assigning with i>0. As soon as you dereference that pointer you're either going to bus-error due to misalignment or, on the off-chance your architecture has no alignment restrictions for float (and most do) you'll start stomping on stack variables with the assignment that follows.
To highlight the error the author is probably trying to get across (that alignment can be important) without introducing undefined behavior aside from that, consider something like this instead:
#include <stdlib.h>
#include <stdio.h>
int main()
{
/* note: defined to hold enough bytes for *two* floats. */
float *fpek = NULL;
char array[2*sizeof(*fpek)];
int i;
/* fill with incrementing values */
for (i=0; i<sizeof(array)/sizeof(array[0]);++i)
array[i] = (i+1);
// now walk the array, one char at a time,
// casting the address of the current element
// to a float pointer and try to read/write it.
fprintf(stderr, "array = %p, size=%lu\n", array, sizeof(array));
for(i=0;i<sizeof(*fpek);++i)
{
fprintf(stderr,"i = %d, ", i);
fpek = (void*)(array+i);
fprintf(stderr, "fpek = %p, ", fpek);
*fpek = i+10;
fprintf(stderr, "*fpek = %.2f\n", *fpek);
}
return 0;
}
No matter how wide/narrow a float is on your system, this will work without introducing undefined behavior specific to walking past the end of your char array. It will quite possibly still bus-error, but at least the UB for exceeding your array subscript is solved.
Running this on my Mac Air (Intel 64bit CPU) produces no bus error:
array = 0x7fff5fbff868, size=8
i = 0, fpek = 0x7fff5fbff868, *fpek = 10.00
i = 1, fpek = 0x7fff5fbff869, *fpek = 11.00
i = 2, fpek = 0x7fff5fbff86a, *fpek = 12.00
i = 3, fpek = 0x7fff5fbff86b, *fpek = 13.00
As you can see, my platform is not particularly finicky about float alignment. your results can (and judging by your prior output, likely will) vary.
Note: the (void*) cast of fpek = (void*)(array+i); may look odd, but this is C, so I can get away with it. The reason I did it was to allow you to demonstrate the other floating point types and see if they have alignment restrictions. As-written you can change just the declaration of fpek at the top of the function to double:
double *fpek = NULL;
Then rerun the program. On my system this produces:
array = 0x7fff5fbff860, size=16
i = 0, fpek = 0x7fff5fbff860, *fpek = 10.00
i = 1, fpek = 0x7fff5fbff861, *fpek = 11.00
i = 2, fpek = 0x7fff5fbff862, *fpek = 12.00
i = 3, fpek = 0x7fff5fbff863, *fpek = 13.00
i = 4, fpek = 0x7fff5fbff864, *fpek = 14.00
i = 5, fpek = 0x7fff5fbff865, *fpek = 15.00
i = 6, fpek = 0x7fff5fbff866, *fpek = 16.00
i = 7, fpek = 0x7fff5fbff867, *fpek = 17.00
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With