c - 结构、指针和铸造核心转储
问题描述
我有一个 30 年前编写的 C 程序(用于 ISAM 文件),其中有一个部分,我可以使用一些帮助来理解/修复。写这篇文章的人看到他/她的评论可能会有未来的问题。它编译得很好,但核心转储。
这是问题行:
altkptr = (struct keydat *)(++header);
函数中的代码:
struct indxheader {
int pnumrecs ;
long pnxtposn ;
int pnextnode ;
long pfreedat ;
int pfreenodes;
#ifdef FIXED_RECLEN
int preclength; /* Added 23-Jun-89 .. kavi */
#endif
int paltkeys ;
};
struct keydat {
int pkeylength,
proot,
pmaxkeys,
pnodesize,
pnumkeys,
pkeyparts ,
*partsarray ;
};
static int buildtables(alloc_flg)
int alloc_flg ; /* if occupy slot etc are to be called */
{
struct indxheader *header ;
struct keydat *altkptr;
int savekey, i ;
int *sptr, *dptr ;
savekey = currkeyno ;
if(seek(0) == ERROR)
reterr(NODSKERR);
if(read(currslot.fd2,ptr2,INXHSZ)<INXHSZ)
reterr(IFLRDERR); /* SIZE OF HEADER BLOCK IN FILE < SIZE DECLARED IN ISNAMES.H */
header = (struct indxheader *)ptr2 ;
currslot.numrecords = header->pnumrecs ; /*added .. if i have luck*/
#ifdef FIXED_RECLEN
currslot.reclength = header->preclength ;
#endif
currslot.nxtposn = header->pnxtposn;
currslot.nextnode = header->pnextnode;
currslot.freedat = header->pfreedat;
currslot.freenodes = header->pfreenodes;
currslot.altkeys = header->paltkeys;
/** If occupyslot to be called then check **/
if ( alloc_flg )
if (alloctable() == ERROR) return (ERROR) ;
altkptr = (struct keydat *)(++header); /* deserves attention..*/
for(currkeyno = 0;currkeyno<currslot.altkeys;currkeyno++) {
currindex.proot = altkptr->proot;
if (currindex.proot == -1) reterr (CRPIXFLERR) ;
currindex.pmaxkeys = altkptr->pmaxkeys;
currindex.pnodesize = altkptr->pnodesize;
currindex.pnumkeys = altkptr->pnumkeys;
currindex.pkeyparts = altkptr->pkeyparts ;
currindex.pkeylength = altkptr->pkeylength ;
altkptr++ ;
sptr = (int *)altkptr ;
if (alloc_flg) {
if ((currindex.partsarray = dptr = (int *)malloc((unsigned)(currindex.pkeyparts*4)*sizeof(int))) == NULL) reterr(MEMORYERR) ;
for (i = 0 ; i<(currindex.pkeyparts*4) ; i++)
*dptr++ = *sptr++ ;
}
else sptr += (currindex.pkeyparts*4) ;
altkptr = (struct keydat *)sptr ;
}
currkeyno = savekey ; /*restore currkeyno to its initial value*/
return (NOERROR);
}
解决方案
header
是一个指向struct indxheader
它被投射到altkptr
哪个是struct keydat
这是:
altkptr = (struct keydat *)(++header);
这相当于:
++header;
altkptr = (struct keydat *) header;
早在 1989 年,选角是否有效可能是一个争论点。但 ...
的增量header
是问题。
在 1989 年, a 与 along
具有相同的sizeof
[因此在struct
] 中对齐int
。这是因为大多数/所有 CPU 都是 32 位(或 16 位)。
现在,您可能在 64 位机器上。所以,long
是64位。
因此,在 1989 年,每个struct
[可能] 的大小都匹配了。现在,尺寸 [可能] 不同
因此, 的增量header
无效。
对于强制 32 位模式编译,您可能会很幸运。-m32
但是,这段代码太摇摇晃晃,否则我会说将它用作[松散的]指南并尽可能重写。
更新:
自 1981 年以来我一直在编写 C 代码,因此我对当时可用的系统有些熟悉。
问题之一是该keydat
结构有一个嵌入的指针,该指针被存储到 ISAM 文件并从 ISAM 文件中读取。
如果是这样,取消引用这样的回读指针几乎肯定会出现段错误或产生不正确的结果。
那是因为不能保证程序已经在同一个地方加载到内存中。
一个关键问题是您是否尝试移植此代码,以便可以读取很久以前创建的现有旧 ISAM 文件。如果没有,最好以现有代码为指导,从头开始重写。
如果您确实必须阅读旧文件,那么准确了解正在运行该软件的系统类型会有所帮助。
如果在那个时代的 PC 上运行 MS/DOS 下,anint
大概是 16 位,along
是 32 位。
如果它在摩托罗拉mc68000
Unix 系统(例如旧的 Sun Microsystems)上运行[我在一家设计和制造类似系统的初创公司],along
是 32 位,但 aint
可以是 16 位或 32 位。大多数系统使用 32 位int
,但是,它是编译器的选择。
此外,PC 是/曾经是小端,但mc68000
Unix 系统是大端。
因此,首先,您必须确定该时代系统的sizeof
for int
、long
和指针。
此外,您需要确定使用了结构成员的对齐方式。
然后,您可能必须重写读取该数据的函数,几乎是逐个字节,并在每个字段的基础上进行转换,以获得要读取的字段的正确字节数及其字节序。
这类似于必须XDR
做的事情。
推荐阅读
- clang - Clang AST Libtooling:如何在 AST 匹配上打印数组标识符
- high-availability - HA 配置问题,ActiveMQ Artemis
- javascript - 如何在 javascript 中获取此值?
- sql - T-SQL 获取数据库中每一行的第 5 个单词
- entity-framework - 包括返回所有记录的导航属性,而不仅仅是添加的属性
- c# - 来自 web api 的 Flutter VideoPlayerController 网络请求
- r - 动态图在 Shiny R 中没有正确显示?
- apache-spark - 如何删除 pyspark 中的模棱两可的列?
- html - Bootstrap 4.5,分离滚动条,让 Div 贴在底部
- python - 只想考虑到目前为止的数据框