cv::format()方法时候对string英文的格式化输出返回乱码

目录

问题提出

问题分析

解决方案

拓展疑问:format函数为什么没有对string做适配

拓展解答:format不是一个泛型函数


问题提出

我在使用cv::String::format()方法时候对string英文的格式化输出返回乱码

对英文字符常量输出正常(OpenCV3.4.7)

string imgname;
string imgname1;
string imgPath;
string imgPath1;

imgname = "DSC02930.JPG";
imgname1 = "DSC02931.JPG";

imgPath = format("G:\\%s", "DSC02930.JPG");//对英文字符常量输出正常
cout << imgname <<endl;
cout << imgPath<<endl;
imgPath1 = format("G:\\%s", imgname1);//对string英文的格式化输出返回乱码
cout << imgname1 << endl;
cout << imgPath1 << endl;

输出结果:

求教原因和解决方案


没人理我,唉,自己继续尝试吧


问题分析

已经知道字符串常量能够正常输出,先来看看char数组的输出

char str[] = "HHHH";
imgPath1 = format("G:\\%s", str);

显然,char数组的输出是没有任何问题的

那为什么std::string和cv::String类型的对象不能正常输出呢??

我开始怀疑

1)难道是直接使用string对象的时候,传递给函数format的是对象的地址?而非其中字符数组的地址?

或者说在函数体内并没有从对象本身做提取得到字符数组的操作?

2)直接使用string对象的时候,传递给函数format的参数默认编码为Unicode等多字节编码?

查看相关调用函数链之后,觉得无从验证,因为我不了解更底层的方法的使用,比如va_list、va_start、vsnprintf

不过从这些已有代码来看的话,应该确实没有从对象本身做提取得到字符数组(即猜想1)

再加上每次得到的乱码都不相同,所以基本可以确认猜想1,否定猜想2。

String format( const char* fmt, ... ){ // core/src/system.cpp
    AutoBuffer<char, 1024> buf;
    for ( ; ; ){
        va_list va;
        va_start(va, fmt);
        int bsize = static_cast<int>(buf.size());
        int len = cv_vsnprintf(buf.data(), bsize, fmt, va);
        va_end(va);

        CV_Assert(len >= 0 && "Check format string for errors");
        if (len >= bsize){
            buf.resize(len + 1);
            continue;
        }
        buf[bsize - 1] = 0;
        return String(buf.data(), len);
    }
}

int cv_vsnprintf(char* buf, int len, const char* fmt, va_list args) { // core/src/system.cpp 
#if defined _MSC_VER
	if (len <= 0) return len == 0 ? 1024 : -1;
	int res = _vsnprintf_s(buf, len, _TRUNCATE, fmt, args);
	// ensure null terminating on VS
	if (res >= 0 && res < len){
		buf[res] = 0;
		return res;
	}
	else{
		buf[len - 1] = 0; // truncate happened
		return res >= len ? res : (len * 2);
	}
#else
	return vsnprintf(buf, len, fmt, args);
#endif
}

int vsnprintf (char * __restrict__ __stream, size_t __n, const char * __restrict__ __format, va_list __local_argv){ // stdio.h
	return __ms_vsnprintf (__stream, __n, __format, __local_argv);
}

解决方案

那么现在我们就想办法从string对象中提取得到关键数据(即字符数组char[]),两种方法

imgname.data());

 查看一下它的源码,直接调用并返回的 (this->_Get_data()._Myptr());

_NODISCARD _Ret_z_ const _Elem * data() const noexcept
{	// return pointer to immutable array
	return (this->_Get_data()._Myptr());
}
imgname.c_str();

查看一下它的源码,同样是直接调用并返回的 (this->_Get_data()._Myptr());

_NODISCARD _Ret_z_ const _Elem * c_str() const noexcept
{	// return pointer to null-terminated immutable array
	return (this->_Get_data()._Myptr());
}

二者除了注释中多了个null-terminated修饰词,以及函数名不同,其他完全一样

奇奇怪怪


拓展疑问:format函数为什么没有对string做适配

虽然现在看来出现这个问题并花费这么多时间显得有点低级

但我还是有点不能理解,既然format函数能够接受string类型对象,为什么会没有对string做适配呢?


拓展解答:format不是一个泛型函数

其实从format函数的源码就能看出来,这不是一个泛型函数,其底层机制的与printf的机制完全一样,并没有对参数列表中的对象进行分析。只要是个地址就行,于是导致了错误

比如我们随便定义一个对象,使用format做%s的输出:

vector<Mat> vm;
imgPath1 = format("G:\\%s", vm);
cout << imgname1 << endl;
cout << imgPath1 << endl;

得到结果:

 

 

 

 

 

 

 

 

 

 

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值