C Solaris和Linux上未对齐的内存访问差异
我在linux(x86,32位)上编写了一个程序,一切正常。但当我尝试在Solaris(SPARC,64位)上编译和运行相同的源代码时,我遇到了一个总线错误(SIGBUS)。来自gdb的消息如下: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
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
来持久化和加载这些结构;如果是后者,那么你的字节顺序问题是打包结构无法解决的,所以你应该手工完成。