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)
    (array)
    在C中是具有相同值的同一表达式,但在几行之内以两种方式编写似乎有点错误。有朝一日,只关心程序中的一些小问题将使您免于一个糟糕的bug,或者有人将操作数的类型更改为一个额外的&生成双间接指针的类型。总之,风格很重要。我不能证明,但我肯定能证明

  • 让事情变得简单。将注意力集中在传递不可能断言的
    静态
    存储类的故障情况上。创建一个完全没有任何内容的新目录,仅将故障案例程序复制到该目录,然后根据CLI,尝试使用
    /whatever
    \whatever
    运行它。在编译之前,请确认没有任何内容运行。确保你正在运行你认为你是的东西

  • 让我们确切地知道您在XP上使用的gnu环境,有几种


我想不出任何好的理由,但半小时后你也没有其他答案,所以我会提出风格投诉和一些猜测和怀疑

  • 请从第一个
    printf()
    中的地址表达式中取出
    &
    。虽然
    (&array)
    (array)
    在C中是具有相同值的同一表达式,但在几行之内以两种方式编写似乎有点错误。有朝一日,只关心程序中的一些小问题将使您免于一个糟糕的bug,或者有人将操作数的类型更改为一个额外的&生成双间接指针的类型。总之,风格很重要。我不能证明,但我肯定能证明

  • 让事情变得简单。将注意力集中在传递不可能断言的
    静态
    存储类的故障情况上。创建一个完全没有任何内容的新目录,仅将故障案例程序复制到该目录,然后根据CLI,尝试使用
    /whatever
    \whatever
    运行它。在编译之前,请确认没有任何内容运行。确保你正在运行你认为你是的东西

  • 让我们确切地知道您在XP上使用的gnu环境,有几种

来自:

请注意,对齐属性的有效性可能会受到链接器中固有限制的限制。在许多系统上,链接器只能安排变量对齐到某个最大对齐。(对于某些链接器,支持的最大对齐可能非常小。)如果链接器最多只能对齐8字节的变量,那么在_属性_中指定对齐(16)仍然只能为您提供8字节对齐。有关更多信息,请参阅链接器文档

我知道为什么断言没有发生,这是因为表达式是真的-不确定表达式为什么是真的,但是在类似这样的情况下,您应该分解它。将以下内容添加到调试语句中:

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