C 使用空心指针和计算的偏移量将值指定给结构的成员
我试图将值分配给函数中的结构成员,该函数接受void*作为参数,然后根据为结构成员计算的偏移量填充数据值C 使用空心指针和计算的偏移量将值指定给结构的成员,c,structure,offset,void,C,Structure,Offset,Void,我试图将值分配给函数中的结构成员,该函数接受void*作为参数,然后根据为结构成员计算的偏移量填充数据值 typedef struct { char C_BFR_LINK[1]; char C_TABLE_DATA[1]; double MF_COD_BALANCE; char C_TYPE_DT[1]; }ANS; 功能 void fillin( void *pp) { double* FVAR; c
typedef struct
{
char C_BFR_LINK[1];
char C_TABLE_DATA[1];
double MF_COD_BALANCE;
char C_TYPE_DT[1];
}ANS;
功能
void fillin( void *pp)
{
double* FVAR;
char* CVAR;
CVAR = pp;
memcpy(CVAR,"I",1);
CVAR = (void *)(pp + 1);
memcpy(CVAR,"S",1);
FVAR = (void *)(pp + 2);
*FVAR = 234.96;
CVAR = (void *) (pp + 10);
memcpy(CVAR,"Z",1);
return ;
}
负责填写相应偏移量1、2和10处的值
我在main中调用此函数,如下所示** ** 我使用gdb进行了调试,在函数中,fillin将值分配给成员,但一旦控件到达主程序,双值就会丢失,这是不正确的
(gdb) p pp
$1 = (void *) 0xffffdabc
(gdb) x /c 0xffffdabc
0xffffdabc: 73 'I'
(gdb) x /c 0xffffdabd
0xffffdabd: 83 'S'
(gdb) n
32 *FVAR = 234.96;
(gdb) n
33 CVAR = (void *) (pp + 10);
(gdb) **x /f 0xffffdabe**
0xffffdabe: 234.96000000000001
57 return 0;
(gdb) **p ans**
$2 = {C_BFR_LINK = "I", C_TABLE_DATA = "S",
**MF_COD_BALANCE = 1.9876540305898699e-268**, C_TYPE_DT = "\213"}
有人能帮我吗?本规范采用gcc 4.4.6 20120305构建。非常感谢任何指针或帮助。编译器将添加“填充”以对齐结构中的某些类型。填充量取决于编译器、编译的处理器、使用的编译器设置等
如“unwind”所述,提供了宏来计算结构中的偏移量,offsetof(type,member)
,它“做正确的事情”。您的代码在两个char变量和实际float变量之间的“nomansland”(填充)中填充一个float,这就是为什么您会得到“随机”结果[显然不是完全随机的-只是“不是您期望的”-如果您知道偏移量的差异,并计算出它提供的浮点值的位模式,则完全可以预测] 使用警告编译
CVAR = (void *)(pp + 1);
这将向您提供警告:算术中使用的“void*”类型的指针
FVAR = (void *)(pp + 2);
*FVAR = 234.96;
CVAR = (void *) (pp + 10);
假设sizeof(double)==8
不是一个好主意正如其他人已经提到的,这是一个非常糟糕的主意,但是,如果您打包结构以避免填充,并使用char*
和sizeof()
您可能可以摆脱它,例如:
typedef struct {
char C_BFR_LINK[1];
char C_TABLE_DATA[1];
double MF_COD_BALANCE;
char C_TYPE_DT[1];
}__attribute__((__packed__)) ANS;
void fillin( void *pp)
{
char* CVAR = pp;
double FVAR = 234.96;
/* sizeof(char) is always one */
memcpy(CVAR, "I", sizeof(char));
CVAR += sizeof(char);
memcpy(CVAR, "S", sizeof(char));
CVAR += sizeof(char);
memcpy(CVAR, &FVAR, sizeof(double));
CVAR += sizeof(double);
memcpy(CVAR,"Z",1);
}
int main()
{
ANS ans;
fillin(&ans);
printf("%c\n", ans.C_BFR_LINK[0]);
printf("%c\n", ans.C_TABLE_DATA[0]);
printf("%c\n", ans.C_TYPE_DT[0]);
printf("%f\n", ans.MF_COD_BALANCE);
return 0;
}
#define offsetof(type, member) __builtin_offsetof (type, member)
CVAR + offsetof(ANS, C_BFR_LINK); //evaluates to 0
CVAR + offsetof(ANS, C_TABLE_DATA); //evaluates to 1
CVAR + offsetof(ANS, MF_COD_BALANCE); //evaluates to 8
CVAR + offsetof(ANS, C_TYPE_DT); //evaluates to 16
这张照片是:
I
S
Z
234.960000
注意:这不适用于不支持未对齐内存访问的体系结构,也可能不支持我不知道的其他问题,因此,一种更方便的方法是让编译器填充结构并使用其他答案建议的offsetof
宏,其计算结果为成员从结构开头的偏移量,例如:
typedef struct {
char C_BFR_LINK[1];
char C_TABLE_DATA[1];
double MF_COD_BALANCE;
char C_TYPE_DT[1];
}__attribute__((__packed__)) ANS;
void fillin( void *pp)
{
char* CVAR = pp;
double FVAR = 234.96;
/* sizeof(char) is always one */
memcpy(CVAR, "I", sizeof(char));
CVAR += sizeof(char);
memcpy(CVAR, "S", sizeof(char));
CVAR += sizeof(char);
memcpy(CVAR, &FVAR, sizeof(double));
CVAR += sizeof(double);
memcpy(CVAR,"Z",1);
}
int main()
{
ANS ans;
fillin(&ans);
printf("%c\n", ans.C_BFR_LINK[0]);
printf("%c\n", ans.C_TABLE_DATA[0]);
printf("%c\n", ans.C_TYPE_DT[0]);
printf("%f\n", ans.MF_COD_BALANCE);
return 0;
}
#define offsetof(type, member) __builtin_offsetof (type, member)
CVAR + offsetof(ANS, C_BFR_LINK); //evaluates to 0
CVAR + offsetof(ANS, C_TABLE_DATA); //evaluates to 1
CVAR + offsetof(ANS, MF_COD_BALANCE); //evaluates to 8
CVAR + offsetof(ANS, C_TYPE_DT); //evaluates to 16
请不要这样做。您的代码假设了很多不正确的事情,您无法手动计算结构成员偏移量,并且是正确的,因为编译器可以出于对齐目的插入填充。如果必须,请使用offsetof
。此外,您对右侧的(void*)
的施法不会产生任何效果。你应该得到编译器的警告,在void*
上的指针算法不是很好。谢谢你的帮助。谢谢David的及时回答。是的,结果是结构填充问题。多亏了大量的mux,我不知道“attribute_uuuuu((uuu-packed))。当然,如果你使用这种处理器架构时“正确”(或“错误”,取决于你怎么看),它会崩溃-例如Sparc,Mips处理器不喜欢读取未正确对齐的数据,因此无法在这些处理器上运行此代码)。我个人认为这不是一个好的解决方案[当然,它在几乎所有的编译器0中都不起作用-据我所知,只有gcc
支持这种特殊形式-其他编译器通常有办法实现同样的效果,但很难实现可移植性]@Matstpeterson我完全同意,但是,如果这是唯一一种不使用
offsetof的方式使代码正常工作,那么假设一个允许未对齐内存访问的体系结构,它只会降低速度,我已经添加了一个注释。是的,我的观点是“不允许编译器按照自己的意愿对齐数据”这使得代码非常不可移植,并且很可能比它应该的速度慢。当然,您可以编写自己的“offsetof”变体,但如果已经有了,那就是浪费时间。