我正在将一个大型的c项目从Windows移植到Unix,并且源代码包含数千次调用的logprint函数,声明如下:
VOID logprint(DWORD level, LPCSTR format, ...);
现在这是我的两个问题:
1。)使用的格式类型说明符不可移植
代码使用%lu
表示ULONG
个变量。在Windows上,这很好,因为ULONG
是unsigned long
的typedef。但是,在移植代码时,我无法重现此typedef,因为根据[MS-DTYP] ULONG
必须始终完全是32位(注意:使用Microsoft的c编译器unsigned long
始终为32位)。
所以我创建了一个Windows类型头文件wtypes.h
,它在stdint.h
和limits.h
的帮助下定义了基本的Windows数据类型。
当然,如果系统%lu
是64位而我的unsigned long
是32位,那么由于ULONG
说明符,这会导致无效读取。所以我还必须向所有(unsigned long)
个logprint参数添加ULONG
强制转换。
ULONG
只是当然的一个例子......
2。)使用的格式类型说明符无效
此外,该代码使用了许多无效的格式说明符。例如。 %d表示DWORD参数。
当然很容易解决:
示例:
替换:
ULONG ulMin, ulMax;
...
logprint(FATAL, "specified interval is invalid %ld..%u out of range",
ulMin, ulMax);
使用:
logprint(FATAL, "specified interval is invalid %lu..%lu",
(unsigned long) ulMin, (unsigned long) ulMax);
但这需要至少两个星期,之后我的大脑会出现乱码。
所以我的实际问题是:
是否有任何自动化工具可以进行这些更改?
作为最低要求,工具必须能够识别参数的类型并使用类型转换为它们添加前缀。一旦有了类型转换,我就可以轻松编写一个修复格式说明符的python脚本。
答案 0 :(得分:1)
logprint
的来源是否可访问?如果是,最好的方法似乎是直接改变它。它必须包含va_arg
的类型转换代码,例如:
ul = va_arg(argp, ULONG);
然后根据需要更改ULONG
。
如果不是,只需让自己的包装函数(如logprint64
执行类似的任务,但根据需要为参数转换类型)。我想,用logprint64
代替logprint
将花费不到一个小时。
或者,您可以重写logprint
。根据您的帖子和回复,logprint
似乎采用以下形式:
#include <stdio.h>
#include <stdarg.h>
enum ErrCode { FATAL, MILD };
typedef unsigned short ULONG;
#define MAX 100
char Buf[MAX];
void logprint(enum ErrCode code, char *fmt, ...)
{
va_list aptr;
va_start(aptr, fmt);
vsprintf(Buf, fmt, aptr);
va_end(aptr);
}
int main()
{
ULONG ulMin = 97, ulMax = 99;
logprint(FATAL,"interval is invalid %c..%c", ulMin, ulMax);
printf("%s\n", Buf);
return(0);
}
您可以使用以下模拟vsprintf
:
void logprint(enum ErrCode code, const char *fmt, ...)
{ // add your types as needed
ULONG h;
unsigned long u;
long d;
int i;
const char *p;
char *buf;
va_list argp;
va_start(argp, fmt);
for (p = fmt, buf = Buf; *p != '\0'; p++) {
if (*p != '%') {
buf += sprintf(buf, "%c", *p); continue;
}
switch (*++p) { // change the type casting as needed
case 'l':
switch (*++p) {
case 'u':
u = (unsigned long) va_arg(argp, ULONG);
buf += sprintf(buf, "%lu", u); continue;
case 'd':
d = va_arg(argp, long);
buf += sprintf(buf, "%ld", d); continue;
}
case 'c':
u = va_arg(argp, unsigned long);
buf += sprintf(buf, "%lu", u); continue;
case 'd':
i = va_arg(argp, int);
buf += sprintf(buf, "%d", i); continue;
}
}
va_end(argp);
}
希望这有帮助。