gpt4 book ai didi

c - __attribute__ ((__aligned__)) 不适用于静态变量

转载 作者:太空宇宙 更新时间:2023-11-04 01:43:08 27 4
gpt4 key购买 nike

这几天一直让我抓狂。如果我将数组声明为 static,则无法让数组对齐 16。

非常感谢任何帮助。

修订版:

#include <stdio.h>
#include <assert.h>

#define MAX_INPUTS 250

int main()
{
float input[MAX_INPUTS] __attribute__ ((__aligned__(16)));
printf("Address of input: %p\n", input);

printf("Assert1: %x\n", ( ((int) (input)) ) );
printf("Assert2: %x\n", ( ((int) (input)) % 16 ) );
printf("Assert3: %x\n", ( ((int) (input)) % 16 ) == 0 );

assert ( ( ((int) (input)) ) );
assert ( ( ((int) (input)) % 16 ) ); /* Fails */
assert ( ( ((int) (input)) % 16 ) == 0 ); /* Passes */

return 0;
}

输出是:

Address of input: 0022FB70
Assert1: 22fb70
Assert2: 0
Assert3: 1
Assertion failed: ( ((int) (input)) % 16 ), file aligntest.c, line 16

正如人们所预料的那样,Assert 2 失败,因为地址以 0 结尾。但是,有:

static float input[MAX_INPUTS] __attribute__ ((__aligned__(16)));

输出是:

Address of input: 00404028
Assert1: 404028
Assert2: 8
Assert3: 1
Assertion failed: ( ((int) (input)) % 16 ), file aligntest.c, line 16

断言 2 仍然失败,尽管结果不为零。当 Assert2 被注释掉时,Assert3 通过(有或没有静态声明)并且程序正常终止。

我在运行 XP Pro 的 Intel Core 2 Duo 上使用 MinGw gcc 4.4.0。

最佳答案

在我工作的机器上(Windows Vista、MinGW gcc 4.3.2),您的代码在任何优化级别都没有为断言生成任何汇编程序!

为了生成断言,我必须想出一个 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 已经在对@Pax 的回答的评论中指出了这一点:

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.

这是解释。 GCC 从源代码中发现输入确实(应该)对齐到 16 字节。它足够聪明,可以完全放弃 assert 并只为 printf 打印出 1。

但是,在链接阶段,链接器无法保证对齐到 16 个字节,而是选择 8 个字节,因为(来自@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.

到那时再将 assert 和未优化的 printf 返回到代码中为时已晚。因此实际的可执行文件不会断言(因为它们已被取出)并且它会打印优化的 1 而不是计算它的运行时间。

volatile 在我的回答中修复它的原因是因为 GCC 不会优化包含 volatile 组件的表达式。它保留 assert 并在运行时正确计算 printf 参数。


如果您不介意声明它比绝对必要的大一点,您可以手动对齐您的数组:

#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;
}

关于c - __attribute__ ((__aligned__)) 不适用于静态变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1468513/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com