- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个静态库 (.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/
我正在构建一个 RCP 应用程序,其中每个季度都会更新功能/插件。因此,如果用户选择自动更新功能/插件,则会下载更新插件的新 jar,但旧插件仍在使用我不再使用的磁盘空间。 我厌倦了删除包含旧 jar
我如何从外部 Controller 功能中调用 Controller 内部的功能,例如电话间隙回调功能 这是 Controller 外部定义的功能 function onDeviceReady()
如果某个功能(例如 MediaSource)可用,我如何使用 Google Dart 检查。 new MediaSource() 抛出一个错误。如何以编程方式检查此类或功能是否存在?有任何想法吗?是否
我正在尝试运行 Azure Orchestrations,突然我开始从 statusQueryGetUri 收到错误: 协调器函数“UploadDocumentOrchestrator”失败:函数“U
我见过 iPhone 上的应用程序,如果在 3.0 上运行,将使用 3.0 功能/API,例如应用内电子邮件编辑器,如果在 2.x 上运行,则不使用这些功能,并退出应用程序以启动邮件相反。 这是怎么做
这是 DB 规范化理论中的一个概念: Third normal form is violated when a non-key field is a fact about another non-ke
如果我定义 #if SOMETHING #endif 而且我还没有在任何地方定义 SOMETHING。 #if 中的代码会编译吗? 最佳答案 当#if的参数表达式中使用的名称未定义为宏时(在所有其他宏
我刚刚澄清了 A* 路径查找应该如何在两条路径具有相等值的 [情况] 下运行,无论是在计算期间还是在结束时,如果有两条相等的短路径。 例如,我在我的起始节点,我可以扩展到两个可能的节点,但它们都具有相
Java有没有类似下面的东西 宏 一种遍历所有私有(private)字段的方法 类似于 smalltalk symbols 的东西——即用于快速比较静态字符串的东西? 请注意,我正在尝试为 black
这个程序应该将华氏度转换为摄氏度: #include int main() { float fahrenheit, celsius; int max, min, step;
当打开PC缓存功能后, 软件将采用先进先出的原则排队对示波器采集的每一帧数据, 进行帧缓存。 当发现屏幕中有感兴趣的波形掠过时, 鼠标点击软件的(暂停)按钮, 可以选择回看某一帧的波形
我有一个特殊的(虚拟)函数,我想在沙盒环境中使用它: disable.system.call eval(parse(text = 'model.frame("1 ~ 1")'), envir = e
使用新的 Service 实现,我是否必须为我的所有服务提供一个 Options 方法? 使用我的所有服务当前使用的旧 ServiceBase 方法,OPTIONS 返回 OK,但没有 Access-
我正在阅读 Fogus 的关于 Clojure 的喜悦的书,在并行编程章节中,我看到了一个函数定义,它肯定想说明一些重要的事情,但我不知道是什么。此外,我看不到这个函数有什么用 - 当我执行时,它什么
我有大量的 C 代码,大部分代码被注释掉和/或 #if 0。当我使用 % 键匹配 if-else 的左括号和右括号时,它也匹配注释掉的代码。 有没有办法或vim插件在匹配括号时不考虑注释掉或#if 0
我有这个功能: map(map(fn x =>[x])) [[],[1],[2,3,4]]; 产生: val it = [[],[[1]],[[2],[3],[4]]] 我不明白这个功能是如何工作的。
我使用 Visual Studio 代码创建了一个函数应用程序,然后发布了它。功能应用程序运行良好。我现在在功能门户中使用代码部署功能(KUDU)并跳过构建。下面是日志 9:55:46 AM
我有一个数据框df: userID Score Task_Alpha Task_Beta Task_Charlie Task_Delta 3108 -8.00 Easy Easy
我真的无法解决这个问题: 我有一个返回数据框的函数。但是,数据框仅打印在我的控制台中,尽管我希望将其存储在工作空间中。我怎样才能做到这一点? 样本数据: n <- 32640 t <- seq(3*p
有没有办法找出所有可能的激活器命令行选项? activator -help仅提供最低限度的可用选项/功能列表,但所有好的东西都隐藏起来,即使在 typesafe 网站在线文档中也不可用。 到目前为止,
我是一名优秀的程序员,十分优秀!