gpt4 book ai didi

c - 通过静态库链接时功能无法正常工作,但如果复制到 prog 中则可以正常工作

转载 作者:太空宇宙 更新时间:2023-11-04 00:27:57 27 4
gpt4 key购买 nike

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

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

这是 lib 中有问题的函数之一(我采用了最简单的函数,它不太依赖于 lib,但我怀疑其他函数无法按预期工作):

#if defined(mingwx64)
typedef long long I64;
#else
typedef long I64;
#endif
typedef unsigned char UI8;

void readParamFile (char* filename, UI8* *Params, I64 *ParamsLen){
FILE* fic;
char* buf; int buf_Len;
*Params=NULL; *ParamsLen=0;

if(!(fic=fopen(filename, "rb"))){
fprintf(stderr, "Error, can't open %s\n", filename);
exit (-1);
}
fseek(fic, 0, SEEK_END);
buf_Len=ftell(fic);
fseek(fic, 0, SEEK_SET);

if(!(buf=(char*)PtrAlloc(sizeof(char)*buf_Len))){
fprintf(stderr, "Error: Can't allocate %d bytes", buf_Len);
exit(-1);
}

//the files are specifics, i read the lines until the first one which doesn't start with #
do{
if(!fgets(buf, buf_Len, fic)){
fprintf(stderr,"Error: Can't read parameters");
exit(-1);
}
buf[strlen(buf)-1]='\0';
} while (buf[0]=='#');

if(!(*Params= (UI8*)PtrAlloc(sizeof(UI8)*strlen(buf)))){
fprintf(stderr,"Error: can't allocate %d butes", buf_Len);
exit(-1);
}

strncpy((char*) *Params , buf, *ParamsLen=strlen(buf));

PtrFree(buf);
fclose(fic);
}

所以,这个函数在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 看起来像它(数字更长):

# Introduction text
000500000000064F1B58372A27

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

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

编辑/解决方案: 所以问题确实是 I64。我设法通过 int64_t 更改它并且它正在工作。此外,我设法重新设置 Makefile 的字体(从 250 行和 16 个目标到 90 行和 5 个目标......),然后发现该体系结构确实已定义......但未包含在任何编译标志中。所以我猜 prog 看不到 I64 被定义为 long long(因为它在 if mingwx64 中)并认为它是一个long,这是这里的大概率。

最佳答案

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

  • #define FILENAME "MyDir\ParamFile.txt"是不正确的。您应该将反斜杠转义为 #define FILENAME "MyDir\\ParamFile.txt"或使用适用于所有 Windows 版本的纯正斜杠:#define FILENAME "MyDir/ParamFile.txt"

  • 类型的任意定义I64有风险。你应该包括 <stdint.h>并使用 typedef uint64_t I64;

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

    int readFile(const char *filename, UI8 **Params, I64 *ParamsLen);

    readFile如果文件无法打开或读取,应返回错误代码。

  • 缺少}exit (-1); 之后在函数中 readFile .

  • 应该为临时缓冲区分配一个额外的字节,以防文件包含没有以换行符结尾的单行。

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

  • 为什么不使用 malloc()而不是特定于非可移植 Windows 的 PtrAlloc() .

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

此函数使用一种扭曲的方法从文件中读取一行。您应该更加努力地理解它的作用并从上述评论中修复它。 C 是一种尖锐和无情的语言,如果没有很好地理解所使用的元素的编程会导致错误和失败,并带来最大的挫败感。

这段代码中和周围的主要问题是类型 I64 的定义。 .由于大量不可移植的 Win32 代码假定 long正好是 32 位,Microsoft 决定保留 long Win64 上的 32 位,更糟糕的是,C 库中对标准 64 位类型的延迟支持,使得 %lld不可移植到 Microsoft Windows 默认库。这解释了您从检查 printf 的一致性的 gcc 编译器得到的警告。带有格式字符串的参数。如果它在 win32 版本中工作,他们可能根本没有使用 64 位值 ( long long)。

对于静态库和在程序中嵌入函数代码之间的不同行为,一个可能的解释是使用了不同的编译器、编译器选项或命令行定义。这些你都检查了吗?您是自己编译该库还是从其他团队以二进制形式获取它?

在 32 位和 64 位架构之间移植软件并非易事,尤其是在鼓励非可移植结构和不稳定的 C99 支持的 Windows 平台上。

代码不仅写得不好,函数原型(prototype)也不正确:Params不是 UI8 *它应该是 UI8 ** ,函数 works 是偶然的,它很容易崩溃。如果开发人员不会对此进行任何更改,我建议一些可能的解决方案:

  • 将函数复制到本地,修复问题,不使用仿库,
  • 编写自己的函数。
  • 在另一家公司找到一份更好的工作:你在那里是在浪费时间,你会从一个更健全的环境中学到更多东西。

关于c - 通过静态库链接时功能无法正常工作,但如果复制到 prog 中则可以正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57376925/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com