这两天将程序移植到64位上,以下代码在32位linux上完全没有问题,但是在64位linux上不能编译通过:
std::vector<char*> vecCharVar;
......
INT32 nprint = vsnprintf(szQuery, sizeof(szQuery), strSQLFormat.c_str(), reinterpret_cast<va_list>(&vecCharVar[0]));
编译时报错:
cannot convert from char** to va_list
在网上查资料,才知道在64位下,va_list已经不是指针了,而是一个24字节的结构体。搜了好多帖子,倒是有人和我遇到了完全一样的问题:
http://stackoverflow.com/questions/11691189/vsprintf-how-to-convert-void-to-va-list-on-linux
http://stackoverflow.com/questions/4535050/how-to-create-a-va-list-on-gcc
网上有各种正确的分析,可以都没有很简便的解决方法。有人提到libffi库可以解决这个问题:
http://www.atmark-techno.com/~yashi/libffi.html -- simple example given
http://www.swig.org/Doc1.3/Varargs.html -- printf() and other examples given
我没有去研究libffi,因为代码中应用很简单,格式化字符串中只有%s,所以手动写了个函数组装动态参数:
bool GetFormatDBStr(string &outStr, string strFormat, vector<const char *> &vecArg)
{
size_t iVecIdx = 0;
string::size_type iStart = 0, iPos;
iPos = strFormat.find("%s", iStart);
while(string::npos != iPos)
{
outStr += strFormat.substr(iStart, iPos - iStart);
if(iPos>iStart && '%'==strFormat.at(iPos-1)) // %前面有转义字符
{
outStr += strFormat.substr(iPos, 2);
}
else
{
if(iVecIdx >= vecArg.size() || NULL == vecArg[iVecIdx])
{
return false;
}
outStr += vecArg[iVecIdx];
iVecIdx++;
}
iStart = iPos + 2;
iPos = strFormat.find("%s", iStart);
}
if(iStart < strFormat.size())
{
outStr += strFormat.substr(iStart, strFormat.size() - iStart);
}
return iVecIdx == vecArg.size();
}
代码从32位移植到64位,比较简单,可是还是会遇到各种问题。引用帖子中一个老外的回复:
You may take it that I was surprised to find this much discrepancy between the 32-bit and 64-bit versions.