__attribute__((__aligned__))无法正常工作与静态变量无法正常、变量、静态、工作

由网友(沃德天.维森陌.拉莫帅啊)分享简介:这是我发疯了好几天。我不能让一个数组对齐到16,如果我把它声明为静态。This has been driving me nuts for days. I can't get an array to align to 16 if I declare it as static.任何帮助非常AP preciated。A...

这是我发疯了好几天。我不能让一个数组对齐到16,如果我把它声明为静态

This has been driving me nuts for days. I can't get an array to align to 16 if I declare it as static.

任何帮助非常AP preciated。

Any help greatly appreciated.

修订稿:

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

#define MAX_INPUTS 250

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

printf("Assert1: %xn", ( ((int) (input))      )        );
printf("Assert2: %xn", ( ((int) (input)) % 16 )        );
printf("Assert3: %xn", ( ((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

正如人们所期望的那样,断言2失败,因为地址0结束。然而,有:

As one would expect, Assert 2 fails because the address ends in 0. However, with:

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通(带或不带静电的声明),并在程序正常终止。

Assert 2 still fails, although the result is non-zero. When Assert2 is commented out, Assert3 passes (with or without the static declaration) and the program terminates normally.

我使用的是英特尔酷睿2双核MinGW的GCC 4.4.0,运行XP专业版。

I'm using MinGw gcc 4.4.0 on an Intel Core 2 Duo, running XP Pro.

推荐答案

在我的机器在工作(Windows Vista中,MinGW的GCC 4.3.2)你的code没有产生任何汇编程序的断言,在任何优化级别!

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!

要获得断言将要产生,我不得不拿出一个挥发性INT 变量和 -O0 标记。

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: %pn", &input);
  addr_as_int = (int)input;
  print_pointer(input);
  print_int(addr_as_int);
  printf("normal int: %08x; int%%16: %02xn", addr_as_int, addr_as_int%16);
  printf("Assert: %dn", (addr_as_int % 16) == 0);
  assert((addr_as_int % 16) == 0); /* Passes */

  printf("Address of input_static: %pn", &input_static);
  addr_as_int = (int)input_static;
  print_pointer(input_static);
  print_int(addr_as_int);
  printf("static int: %08x; int%%16: %02xn", addr_as_int, (addr_as_int)%16);
  printf("Assert: %dn", (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.

更新1(@Pax加入@Falaina的建议 - 我们都建议你接受这一个,如果它原来是如此):的

其实我觉得@Falaina已经钉在一个注释@大同的回答:

Actually I think @Falaina has nailed it in a comment to @Pax's answer:

只是一个建议。你编译与优化?这是可能的编译器巧言令色中去嘿,这个变量对齐到16字节,显然地址%16 0,用1替换所有的检查只是一个想法。

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从源$ C ​​$搞清楚c表示输入确实(应该是)对齐到16个字节。这是足够聪明的下降断言取值,合共只打印出1对的printf 秒。

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 asserts altogether and to just print out 1 for the printfs.

然而,在链路阶段,接头是不能保证对准到16字节,而不是选择了8,因为(来自@Pax):

However, at the link stage, the linker is not able to guarantee alignment to 16 bytes, instead opting for 8 because (from @Pax):

需要注意的是对齐属性的有效性可通过您的链接器固有的限制是有限的。在许多系统中,接头是唯一能够安排变量对齐到一定最大对齐。 (对于某些接头,所支持的最大取向可能是非常非常小。)如果连接体仅能够对准变量达到最大8字节对齐,则指定对准(16)在一个__attribute__将仍然只为你提供8字节对齐。请参阅链接器文档以获取更多信息。

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.

到那时为时已晚,以获得断言和非优化的printf 发回至code。因此,实际的可执行文件将不能断言(因为他们已经被取出来),它会打印出优化的1,而不是计算它的运行时间。

By then it's too late to get the asserts and non-optimized printfs 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.

究其原因,挥发性修复它在我的回答是,因为GCC不会优化含有挥发性成分的前pressions。它离开断言 S在和正确计算的printf 参数在运行时。

The reason the volatile fixes it in my answer is because GCC will not optimize the expressions that contain volatile components. It leaves the asserts in and calculates the printf arguments at runtime properly.

您可以手动调整您的数组,如果你不介意的声明比stricly需要一点点大的:

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: %pn", misaligned_input);
  printf("Address of input: %pn", input);
  printf("Assert1: %xn", ( ((int) (input))                 )      );
  printf("Assert2: %xn", ( ((int) (input)) % ALIGNMENT_REQ )      );
  printf("Assert3: %xn", ( ((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;
}