【问题标题】:Why sem_t pointer have to start at multiple of 4 offset?为什么 sem_t 指针必须从 4 偏移量的倍数开始?
【发布时间】:2017-05-21 17:56:01
【问题描述】:

当您访问内存块(实际情况下使用 mmap 为 fe)时,sem_t 的正确指针必须是 4 的倍数。如果不是,那么 sem_init() 仍然不会返回 -1(错误值),但是sem_t 无效。为什么会这样?

下面的代码显示了信号量的行为。

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <strings.h> //bzero

int main(int argc, const char *argv[]) {
  //sizeof(sem_t) == 32 on 86_64, 16 on 86
  void *adrr = malloc(sizeof(sem_t)*2);
  bzero(adrr, sizeof(sem_t)*2); 

  sem_t *sem1 = adrr+1;
  if(sem_init(sem1, 1, 0) == -1) printf("ERROR\n");
  sem_wait(sem1);
  printf("Not working\n");
  bzero(adrr, sizeof(sem_t)*2);

  sem_t *sem2 = adrr+2;
  sem_init(sem2, 1, 0);
  sem_wait(sem2);
  printf("Not working\n");
  bzero(adrr, sizeof(sem_t)*2); 

  sem_t *sem3 = adrr+3;
  sem_init(sem3, 1, 0);
  sem_wait(sem3);
  printf("Not working\n");
  bzero(adrr, sizeof(sem_t)*2);

  sem_t *sem4 = adrr+4;
  sem_init(sem4, 1, 0);
  sem_wait(sem4);
  printf("Working\n");
  free(adrr);
  return 0; 
}

【问题讨论】:

  • The POSIX sem_init reference 没有说明必须将sem_t 对象放置在可被 4 整除的地址上。您从哪里获得这些信息?
  • 将 1 添加到 void 指针(即adrr)似乎很奇怪。见stackoverflow.com/questions/6449935/…
  • 我对此一无所知,但是当我运行上面的代码时,只有最后一个指针指向的信号量正常工作。
  • 您应该传递一个指向有效对齐的sem_t 结构的指针。如果传递的指针未如此对齐,则会得到未定义的行为。您必须使用 GCC。标准 C 不允许对 void 指针进行算术运算。
  • 当函数的参数:main()未使用时,则使用签名:int main( void )

标签: c linux posix


【解决方案1】:
C 中的

ALL1 类型可能有对齐要求。这些要求总是由实现定义的,并且在不同的架构上甚至在同一架构上的不同编译器上可能会有所不同(尽管这种情况很少见)。

违反实现定义的对齐要求会导致未定义的行为——任何事情都可能发生,但通常情况是程序在访问未对齐的对象时出错或崩溃。

您似乎已经确定,在您的具体实现中,sem_t 的对齐要求为 4——在 32 位架构上相当常见。其他实现可能会有所不同。


1你可以说char从来没有对齐要求,或者它的对齐要求是1

【讨论】:

  • FWIW:(64 位)Mac 上的 32 位编译允许 double 进行 4 字节对齐,但同一台机器上的 64 位编译需要 8 字节对齐。
  • “虽然这很罕见” - 我不会签那个。 AFAIK long double 在 x86 上有不同的对齐方式,具体取决于 ABI(它不仅是指定对齐方式和类型布局的架构)。 1 字节是所有其他类型的对齐单位,所以不,char 没有对齐要求。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-19
  • 1970-01-01
  • 2013-04-16
  • 2012-10-30
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
相关资源
最近更新 更多