C __属性_uuu((uuu对齐_uuu))不使用静态变量
这几天我都快发疯了。如果将数组声明为C __属性_uuu((uuu对齐_uuu))不使用静态变量,c,memory,gcc,alignment,C,Memory,Gcc,Alignment,这几天我都快发疯了。如果将数组声明为静态,则无法使其与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("Assert
静态
,则无法使其与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;
}
正如所料,断言2失败,因为地址以0结尾。然而,对于:
static float input[MAX_INPUTS] __attribute__ ((__aligned__(16)));
输出为:
Address of input: 0022FB70
Assert1: 22fb70
Assert2: 0
Assert3: 1
Assertion failed: ( ((int) (input)) % 16 ), file aligntest.c, line 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。我想不出任何好的理由,但在半个小时后,您也没有任何其他答案,因此我将提出风格投诉和一些猜测和怀疑
- 请从第一个
中的地址表达式中取出printf()
。虽然&
和(&array)
在C中是具有相同值的同一表达式,但在几行之内以两种方式编写似乎有点错误。有朝一日,只关心程序中的一些小问题将使您免于一个糟糕的bug,或者有人将操作数的类型更改为一个额外的&生成双间接指针的类型。总之,风格很重要。我不能证明,但我肯定能证明(array)
- 让事情变得简单。将注意力集中在传递不可能断言的
存储类的故障情况上。创建一个完全没有任何内容的新目录,仅将故障案例程序复制到该目录,然后根据CLI,尝试使用静态
或/whatever
运行它。在编译之前,请确认没有任何内容运行。确保你正在运行你认为你是的东西\whatever
- 让我们确切地知道您在XP上使用的gnu环境,有几种
- 请从第一个
中的地址表达式中取出printf()
。虽然&
和(&array)
在C中是具有相同值的同一表达式,但在几行之内以两种方式编写似乎有点错误。有朝一日,只关心程序中的一些小问题将使您免于一个糟糕的bug,或者有人将操作数的类型更改为一个额外的&生成双间接指针的类型。总之,风格很重要。我不能证明,但我肯定能证明(array)
- 让事情变得简单。将注意力集中在传递不可能断言的
存储类的故障情况上。创建一个完全没有任何内容的新目录,仅将故障案例程序复制到该目录,然后根据CLI,尝试使用静态
或/whatever
运行它。在编译之前,请确认没有任何内容运行。确保你正在运行你认为你是的东西\whatever
- 让我们确切地知道您在XP上使用的gnu环境,有几种
printf("Assert1: %x\n", ( ((int) (input))));
printf("Assert2: %x\n", ( ((int) (input)) % 16 ));
printf("Assert3: %x\n", ( ((int) (input)) % 16 ) == 0);
并向我们展示结果
还要检查您正在运行的gcc版本-4.3.1及更早版本是否与对齐。Cygwin似乎同时拥有gcc3和gcc4软件包,假设您正在使用这些软件包——如果没有,请检查版本
更新1:事实上,我认为@Falaina已经在下面的评论中明确了这一点。这里有一个合理的解释
GCC从源代码中发现输入确实(应该)与16字节对齐。它足够聪明,可以完全删除断言,只为printf打印1
然而,在链接阶段,链接器(没有GCC那样的功能)不能保证对齐到16字节,而是选择8字节(见我上面的引用)。到那时,将断言和未优化的printf返回到代码中已经太晚了。因此,实际的可执行文件不会断言(因为它们已被取出),它将打印优化的1,而不是在运行时计算它
volatile在@pmg的答案中修复它的原因是因为GCC不会优化包含volatile组件的表达式。它保留断言,并在运行时正确计算打印参数
如果事实证明是这样的话,这无疑是我见过的最棘手的问题之一。我不敢说这是一个bug,因为gcc和ld都像广告中所宣传的那样——这是各种因素的组合在把事情搞砸。来自:
请注意,对齐属性的有效性可能会受到链接器中固有限制的限制。在许多系统上,链接器只能安排变量对齐到某个最大对齐。(对于某些链接器,支持的最大对齐可能非常小。)如果链接器最多只能对齐8字节的变量,那么在_属性_中指定对齐(16)仍然只能为您提供8字节对齐。有关更多信息,请参阅链接器文档
#include <stdio.h>
#include <string.h>
void print_pointer(void *ptr) {
unsigned char data[sizeof (void*)];
size_t k;
memmove(data, &ptr, sizeof (void*));
printf("ptr: ");
for (k=0; k<sizeof (void*); k++) {
printf(" %02x", data[k]);
}
puts("");
}
void print_int(int value) { /* ... */ }
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;
}
#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;
}