C 通过静态库链接时功能不正常,但在程序中复制时功能正常

C 通过静态库链接时功能不正常,但在程序中复制时功能正常,c,static-libraries,win64,C,Static Libraries,Win64,我有一个静态库(.a),其中包含一些在另一个程序中使用的有用函数。 链接进行得很顺利,找到了库中的函数,但是当程序执行时,它就不能正常工作。另一方面,如果我直接在程序代码中复制/粘贴我需要的lib函数,它工作得很好。此外,它在win32上运行良好,但现在我使用的是Win64 Edit:我知道代码很糟糕(不是我的),但直接复制到prog中时,它仍能正常工作,这意味着开发人员不会对其进行任何更改。我需要理解的是,当我链接函数所在的库时,为什么它不能很好地工作,而它在Linux64和Win32上工作得

我有一个静态库(.a),其中包含一些在另一个程序中使用的有用函数。 链接进行得很顺利,找到了库中的函数,但是当程序执行时,它就不能正常工作。另一方面,如果我直接在程序代码中复制/粘贴我需要的lib函数,它工作得很好。此外,它在win32上运行良好,但现在我使用的是Win64

Edit:我知道代码很糟糕(不是我的),但直接复制到prog中时,它仍能正常工作,这意味着开发人员不会对其进行任何更改。我需要理解的是,当我链接函数所在的库时,为什么它不能很好地工作,而它在Linux64和Win32上工作得很好。您可能会在这段代码中发现很多问题,但这只是一个示例;因为它没有解释为什么它在prog中工作,但没有被lib链接,所以它对我来说毫无用处,因为开发人员根本不关心它。

下面是lib中有问题的函数之一(我使用了最简单的函数,它对lib的依赖性不大,但我怀疑其他函数没有按预期工作):

这个函数在MyLib.a中。我使用Mingw64在Win64上编译它(就像我在Win32上使用Mingw一样),编译工作正常。 然后,在编译MyProg时,我链接这个库。汇编进展顺利。 当我启动MyProg时,它会在某个时候使用此功能,并在
strncpy
上停止(之前使用了
memcpy
,但效果并不好)。它不会抛出任何错误消息,什么也没有:我等了一会儿,程序停止了,就好像它做得很好一样,只是没有。如果我尝试在这个
strncpy
之后进行打印,它永远不会转到它,但是程序结束“正常”(我看不到崩溃)

奇怪的是,如果我把这个函数复制/粘贴到MyProg的代码中,比如说我称它为
readFileBis
,那么
readFileBis
工作得很好

然而,我不会在每个需要它的程序中复制/粘贴库的每个函数。那将是一种浪费

编辑:试图为其制作一个可复制的示例,但仍在进行。假设这是MyProg的唯一文件:

MyProg.c

#define FILENAME "MyDir/ParamFile.txt"

void readParamFileBis (char* filename, UI8* *Params, I64 *ParamsLen){
    //the exact same thing as in readFile, don't wanna make the question too long.
}

int main(int argc, char *argv[]){

    UI8 *Params = NULL; 
    I64 ParamsLen = 0;

//this is working:
    readParamFileBis (FILENAME, &Params, &ParamsLen);
//this is not working : 
    readParamFile (FILENAME, &Params, &ParamsLen);

    exit(0);
}
ParamFile.txt看起来很像(数字更长):

我想知道这里可能出了什么问题。知道它在Win32上运行良好,我想它与64位的东西有关,但我不知道是什么。因为我在win64上重新编译了lib和prog,所以应该没问题。我不知道发生了什么事

哦,还有一件奇怪的事情可能与此有关,也可能与此无关:在编译时,我可能会使用标志-D${ARCHI}。在Win32上,ARCHI是
mnigw386
;在win64上,它是
mingwx64
。当我在Win64上使用此标志进行编译时,我得到了一些关于我的打印格式的警告(例如,我正在使用%ld打印一些在win32上没有的I64,但它不喜欢)


编辑/解决方案:所以问题确实出在I64上。我设法通过
int64\t
更改了它,它正在工作。此外,我成功地重新发布了Makefiles(从250行和16个目标到90行和5个目标…),然后发现架构确实已经定义了…但没有包含在任何编译标志中。所以我猜prog看不到
I64
被定义为
long
(因为它在
中,如果mingwx64
),并且认为它是
long
,这是这里的大问题

Windows是LLP64而不是LP64;只有在为x64编译时,I64才只有32位,高位作为垃圾传递

请务必包含,并使用诸如int64_t和uint64_t之类的类型来避免此类错误


不纠正错误的定义是行不通的。如果必须,请使用应用修补程序的生成过程,但要使用工作类型定义。

发布的代码片段中存在多个问题:

  • #定义文件名“MyDir\ParamFile.txt”
    不正确。您应该将反斜杠转义为
    #定义文件名“MyDir\\ParamFile.txt”
    ,或者使用适用于所有Windows版本的普通正斜杠:
    #定义文件名“MyDir/ParamFile.txt”

  • 类型
    I64
    的任意定义是有风险的。您应该包括
    并使用
    typedef uint64

  • 函数原型
    void readFile(char*filename,UI8*Params,I64*ParamsLen)
    与预期的API不一致:
    readFile
    读取文件内容,并将指向已分配缓冲区长度
    *ParamsLen
    的指针存储到
    *Params
    中。原型应为:

    int readFile(const char *filename, UI8 **Params, I64 *ParamsLen);
    
    readFile
    应返回错误代码,以防文件无法打开或读取

  • 退出(-1)后缺少
    }
    在函数
    readFile

  • 临时缓冲区应该分配一个额外的字节,以防文件包含一行,而不是以换行符结尾

  • fgets()
    不一定在数组末尾存储
    '\n'
    ,尤其是当文件不包含一个时。无条件剥离最后一个字符是不正确的

  • 为什么不使用
    malloc()

  • 如果希望将文件内容用作C字符串,则应为空终止符分配额外的字节,并将其存储在数组的末尾

此函数使用扭曲的方法从文件中读取行。你应该更努力地理解它的作用,并从上面的评论中修正它。C是一种犀利而无情的语言,编程时没有很好的理解元素
# Introduction text
000500000000064F1B58372A27
int readFile(const char *filename, UI8 **Params, I64 *ParamsLen);
void readParamFile (char* filename, UI8 *Params, I64 *ParamsLen){
*Params=NULL
*Params= (UI8*)PtrAlloc(sizeof(UI8)*strlen(buf))
void readParamFile (char* filename, UI8 **Params, I64 *ParamsLen)
#include <stdio.h>
#include <string.h>
#include <stdint.h>

int readParamFileBis( const char *filename, unsigned char **params, uint64_t *paramsLen )
{
    *params = NULL;

    FILE *fp = fopen( filename, "r" );
    if ( fp == NULL )
    {
        return( -1 );
    }

    // assume we have POSIX getline()
    // (Windows implementations abound...)
    unsigned char *line = NULL;
    size_t lineLen = 0UL;

    // loop until a line that doesn't start with # is found
    for ( ;; )
    {
        ssize_t bytesRead = getline( &line, &lineLen, fp );

        // EOF - no more to read
        if ( bytesRead == -1 )
        {
            break;
        }

        // line starts with # - skip it
        if ( line[ 0 ] == '#' )
        {
            continue;
        }

        // we found the first line that
        // doesn't start with #, so pass
        // it back to the caller

        // strip any trailing newline
        line[ strcspn( "\n" ) ] = '\0';

        // assume we have POSIX strdup()
        // (could just do *params = line; but
        // line could now refer to a vary large buffer
        // if a long comment line was in the file)
        *params = strdup( line );

        // tell the caller how long the line is
        // (extraneous as it's a string, but...)
        *ParamsLen = strlen( line );

        free( line );

        // found the line, so break the loop
        break;
    }

    fclose( fp );

    // didn't find a line that doesn't start with '#'
    if ( *params == NULL )
    {
         return( -1 );
    }

    // success
    return( 0 );
} 
char *readParamFile( char* filename )
{
    FILE *fp = fopen( filename, "r" );
    if ( fp == NULL ) return( NULL );

    unsigned char *line = NULL;
    size_t lineLen = 0UL;

    for ( ;; )
    {
        ssize_t bytesRead = getline( &line, &lineLen, fp );
        if ( bytesRead == -1 ) break;
        if ( line[ 0 ] == '#' ) continue;

        line[ strcspn( "\n" ) ] = '\0';
        break;
    }

    fclose( fp );

    // oops!  Don't return a comment line!
    // could also strdup( line ) in loop above after finding proper line
    if ( line != NULL && line[ 0 ] == '#' )
    {
        free( line );
        line = NULL:
    }
    return( line );
}