首页 > 解决方案 > 结构、指针和铸造核心转储

问题描述

我有一个 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);
}

标签: cpointersdata-structurescasting

解决方案


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 位。

如果它在摩托罗拉mc68000Unix 系统(例如旧的 Sun Microsystems)上运行[我在一家设计和制造类似系统的初创公司],along是 32 位,但 aint可以是 16 位或 32 位。大多数系统使用 32 位int,但是,它是编译器的选择。

此外,PC 是/曾经是小端,但mc68000Unix 系统是大端。

因此,首先,您必须确定该时代系统的sizeoffor intlong和指针。

此外,您需要确定使用了结构成员的对齐方式。

然后,您可能必须重写读取该数据的函数,几乎是逐个字节,并在每个字段的基础上进行转换,以获得要读取的字段的正确字节数及其字节序。

这类似于必须XDR做的事情。


推荐阅读