C Solaris和Linux上未对齐的内存访问差异

C Solaris和Linux上未对齐的内存访问差异,c,linux,solaris,memory-alignment,C,Linux,Solaris,Memory Alignment,我在linux(x86,32位)上编写了一个程序,一切正常。但当我尝试在Solaris(SPARC,64位)上编译和运行相同的源代码时,我遇到了一个总线错误(SIGBUS)。来自gdb的消息如下: gdb) where #0 0xff2aa57c in number () from /lib/libc.so.1 #1 0xff2a9a70 in __doscan_u () from /lib/libc.so.1 #2 0xff2b0014 in vsscanf () from /lib/l

我在linux(x86,32位)上编写了一个程序,一切正常。但当我尝试在Solaris(SPARC,64位)上编译和运行相同的源代码时,我遇到了一个总线错误(SIGBUS)。来自gdb的消息如下:

gdb) where
#0  0xff2aa57c in number () from /lib/libc.so.1
#1  0xff2a9a70 in __doscan_u () from /lib/libc.so.1
#2  0xff2b0014 in vsscanf () from /lib/libc.so.1
#3  0xff2aeb90 in fscanf () from /lib/libc.so.1
#4  0x00010940 in main (argc=4, argv=0xffbff48c) at wHeap.c:22
while( fscanf(input,"%[^,],%hu,%u,%u,%[^\n]\n",record.name,&record.race,&record.class,&record.id,record.guild) != EOF){
......
}
#pragma pack(1)
typedef struct {                                                          
     char name[MAXNAME];                                                       
     unsigned short race;                                                  
     unsigned int class;                                                   
     unsigned int id;                                                      
     char guild[MAXGUILD];                                                       
}record;
原来这个bug是因为fscanf函数而发生的,对应的代码剪贴如下:

gdb) where
#0  0xff2aa57c in number () from /lib/libc.so.1
#1  0xff2a9a70 in __doscan_u () from /lib/libc.so.1
#2  0xff2b0014 in vsscanf () from /lib/libc.so.1
#3  0xff2aeb90 in fscanf () from /lib/libc.so.1
#4  0x00010940 in main (argc=4, argv=0xffbff48c) at wHeap.c:22
while( fscanf(input,"%[^,],%hu,%u,%u,%[^\n]\n",record.name,&record.race,&record.class,&record.id,record.guild) != EOF){
......
}
#pragma pack(1)
typedef struct {                                                          
     char name[MAXNAME];                                                       
     unsigned short race;                                                  
     unsigned int class;                                                   
     unsigned int id;                                                      
     char guild[MAXGUILD];                                                       
}record;
基本上,我尝试从逗号分隔的值文件中提取信息,并将其存储在结构数组(记录)中,例如:

Rod'rod,1,4,103026,Project Peace
Ceru,1,6,89351,World Keepers
Belget,2,9,246708,Radiant Heaters
记录结构如下所示:

gdb) where
#0  0xff2aa57c in number () from /lib/libc.so.1
#1  0xff2a9a70 in __doscan_u () from /lib/libc.so.1
#2  0xff2b0014 in vsscanf () from /lib/libc.so.1
#3  0xff2aeb90 in fscanf () from /lib/libc.so.1
#4  0x00010940 in main (argc=4, argv=0xffbff48c) at wHeap.c:22
while( fscanf(input,"%[^,],%hu,%u,%u,%[^\n]\n",record.name,&record.race,&record.class,&record.id,record.guild) != EOF){
......
}
#pragma pack(1)
typedef struct {                                                          
     char name[MAXNAME];                                                       
     unsigned short race;                                                  
     unsigned int class;                                                   
     unsigned int id;                                                      
     char guild[MAXGUILD];                                                       
}record;

您可能会注意到,我使用pragma包试图防止这两台机器之间的对齐差异。

您的结构是如何定义的

像这样

struct X {
  char name[MAXNAME],
  short race,
  unsigned class,
  unsigned id,
  char guild[MAXGUILD],
  /* possibly more members ... */
};

如果不同,则scanf转换规范与参数不匹配。

如何定义结构

像这样

struct X {
  char name[MAXNAME],
  short race,
  unsigned class,
  unsigned id,
  char guild[MAXGUILD],
  /* possibly more members ... */
};

如果不同,则scanf转换规范与参数不匹配。

Solaris机器是否运行在比x86更难对齐的硬件上


您在pmg的回答中的评论意味着您已经关闭了填充,这将在例如上触发此类错误。

Solaris机器是否运行在比x86更难对齐的硬件上


您在pmg回答中的评论意味着您已关闭填充,这将在上触发此类错误。例如:

您不能获取压缩结构的非
char
元素的地址并通过该指针访问该元素。通常,您应该不要使用压缩结构。它们是一种严重的代码气味,表明您可能正在做一些可怕的错误。如果您不顾所有合理的请求坚持保留压缩结构,您可以使用中间变量并将它们的地址传递给
scanf
,然后将其赋值到
结构中

,您不能获取压缩结构的非
字符
元素的地址并通过该指针访问该元素。通常,您应该不要使用压缩结构。它们是一种严重的代码气味,表明您可能正在做一些可怕的错误。如果您不顾所有合理的要求坚持保留压缩结构,您可以使用中间变量并将它们的地址传递给
scanf
,然后分配到
struct

SIGBUS
通常表示对齐异常或试图访问物理上不存在的内存(可能是某些设备MMIO空间中不存在的地址)


许多体系结构中的Linux都模拟未对齐的加载/存储,对于SPARC,请查看
arch/SPARC/kernel/unaligned.c
arch/SPARC/kernel/una_asm.S
。Linux/ARM有一个sysctl,它允许您选择是否在未对齐的内存访问上崩溃/记录和静默地模拟/模拟。显然,Linux/SPARC没有同等的功能sysctl.

SIGBUS
通常表示对齐异常或试图访问物理上不存在的内存(可能是某些设备MMIO空间中不存在的地址)


许多体系结构中的Linux都模拟未对齐的加载/存储,对于SPARC,请查看
arch/SPARC/kernel/unaligned.c
arch/SPARC/kernel/una_asm.S
。Linux/ARM有一个sysctl,它允许您选择是否在未对齐的内存访问上崩溃/记录和静默地模拟/模拟。显然,Linux/SPARC没有同等的功能sysctl.

真的吗?字符串不应该是实际的字符数组吗?@pmg name和guild是固定大小的字符数组,结构使用#pragma pack(1)防止对齐啊!
#pragma
…尝试不使用它(可能是将短字符对齐到Solaris不喜欢的对齐方式)不要使用
#pragma pack
或任何类似的东西。@spud86:
arch/sparc/kernel/unaligned.c
arch/sparc/kernel/una_asm.S
看起来是这样的。真的吗?字符串不应该是实际的字符数组吗?@pmg名称和行会是固定大小的字符数组,结构使用的是#pragma pack(1)为了防止对齐啊!
#pragma
…尝试不使用它(可能是将短字符对齐到Solaris不喜欢的对齐方式),不要使用
#pragma pack
或任何类似的东西。@Spudd86:
arch/sparc/kernel/unaligned.c
arch/sparc/kernel/una#asm.S
看起来像它。向我们展示结构的定义(
record
)。向我们显示结构的定义(
record
).是的,问题是我真的需要打包,而你的解决方案实际上很有效,thx很多。@flyingV:你确定你需要打包吗?如果你向一个硬件发送字节,那么我可以看到它,但不是像这样的东西,除非你很懒,并且使用
fwrite
fread
来持久化和加载这些结构;如果是后者,那么你有字节顺序问题,而打包的结构无法解决,所以你应该手工完成。是的,问题是我真的需要打包,而你的解决方案实际上很有效,thx很多。@flyingV:你确定你需要在这里打包吗?如果你将字节发送到一个硬件,那么我可以看到,但没有除非你很懒,使用
fwrite
fread
来持久化和加载这些结构;如果是后者,那么你的字节顺序问题是打包结构无法解决的,所以你应该手工完成。