在我工作的機器上(Windows Vista,MinGW gcc 4.3.2),您的代碼在任何優化級別都沒有生成任何assert的彙編器!
爲了得到要生成的斷言,我不得不想出volatile int
變量並編譯-O0
標誌。
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;
}
我不知道爲什麼編譯器選擇從對象文件中刪除斷言。我快速谷歌搜索沒有透露任何有趣的。
更新1(@Pax在@Falaina的建議添加 - 我們都建議你接受這一個,如果它原來是如此):
其實我覺得@Falaina在已經釘它評論@帕克斯的回答:
只是一個建議。你是否在編譯優化?編譯器可能會嘗試變得聰明,並且「嘿,這個變量對齊到16個字節,顯然地址是%16」,並用1替換所有的檢查。只是一個想法。
下面是解釋。 GCC從源代碼中確定輸入確實(應該是)對齊到16個字節。它足夠聰明,完全可以刪除assert
,只需打印1就可以得到printf
。
然而,在鏈路級,所述接頭是不能保證對準到16個字節,而不是選擇爲8,因爲(來自@Pax):
注意,對齊屬性的有效性可被限制通過鏈接器的固有限制。在很多系統上,鏈接器只能將變量排列成一定的最大對齊。 (對於某些連接器,支持的最大對齊可能非常小)。如果鏈接器只能對齊最多8個字節對齊的變量,則在__attribute__中指定對齊(16)仍然只能爲您提供8字節對齊。有關更多信息,請參閱鏈接器文檔。
到時候把assert
和非優化的printf
回到代碼中已經太遲了。所以實際的可執行文件不會斷言(因爲它們已被取出),它將打印優化的1而不是計算它的運行時間。
volatile
修復它在我的答案是因爲GCC不會優化包含易失組件的表達式。它將離開assert
並在運行時正確計算printf
參數。
您可以手動調整您的數組,如果你不介意的聲明比stricly需要大一點:
#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;
}
@Ian,檢查出的除了@ PMG的答案 - 我想你在那裏可以找到足夠好的問題(以及解決方案,即引入揮發性物質以阻止gcc對其優化的瘋狂追求)。 – paxdiablo 2009-09-24 13:19:57
@Ian,重新更新:由於相同的原因,assert2將會*總是*失敗。assert3將*總是*傳遞(無論地址是否實際上由鏈接器對齊)。 GCC *認爲*它將會對齊,並會拋出assert1/3,並可能將assert2優化爲assert(0)。 – paxdiablo 2009-09-24 13:42:58
查看我的(第二個)答案的最新更新 – pmg 2009-09-25 12:02:49