目的:在windows系统写c++项目,常用sscanf_s进行格式化输入。但是在ubuntu系统上发现sscanf_s不可用(只有sscanf可用,但是它是c++ 99 的函数了)。后面查阅知道,这个sscanf_s函数是微软专有的函数,不具有跨平台特点。
问题:
在ubuntu系统中,使用sscanf_s函数,发现它不在是std命名空间的函数。见下图:
追溯sscanf_s函数所在的文件<stdio.h>,发现只有sscanf函数,没有sscanf_s函数。
查阅的资料:
查阅资料发现sscanf_s这个函数是微软包装了sscanf,它弥补了标准库函数sscanf函数的安全缺陷。因此sscanf_s在windows系统中已经打包好了,在vs平台可以直接使用,但是在ubuntu 系统中没有sscanf_s函数。
查看sscanf_s,可以参考微软的链接,可以找到sscanf_s,它的具体实现和用法,见下图:
解决的办法:
出现上述的问题有两种方法可以解决
1)使用标准库的函数sscanf代替sscanf_s。
2)使用c++中的iostream流格式化输入,代替上述的功能。
第一种方法替代方案很简单,如果使用标准的sscanf,它的代码可以替换如下:
std::sscanf(idxs.c_str(), "%d/%d", &vi, &vti);
这种格式化输入也可以得到相应的结果。
第二种,较为实用,建议使用iostream解决,给出代码样例如下。
bool ReadFromObjFile(const std::string& path)
{
std::ifstream fh(path);
if(fh.fail())
{
std::cerr << "failed to open " << path << std::endl;
return false;
}
std::vector<Eigen::Vector3d> vertices;
std::vector<Eigen::Vector2d> v_vt;
std::string str;
bool has_vt; //vertex uv
int faces_count = 0; //count face number
while(std::getline(fh, str))
{
if(str.empty())
continue;
std::stringstream ss(str);
std::string pattern;
ss >> pattern;
if(pattern == "v")
{
Eigen::Vector3d v;
ss >> v[0] >> v[1] >> v[2];
vertices.emplace_back(v);
}
if(pattern == "vt")
{
Eigen::Vector2d v;
ss >> v[0] >> v[1];
v_vt.emplace_back(v);
}
if(pattern == "f")
{
HWPolygon* polygon = new HW::HWPolygon();
//has_vt =
has_vt = (v_vt.size() == vertices.size());
if(has_vt)
{
std::string idxs;
while(ss >> idxs)
{
int vi, vti;
std::string item;
std::stringstream ssidx(idxs);
std::getline(ssidx, item, '/');
vi = std::stol(item);
std::getline(ssidx, item);
vti = std::stol(item);
//debug delete later...
std::cerr << "vi item: " << vi << std::endl;
std::cerr <<"vti item: " << vti << std::endl;
}
}
else
{
int idx;
while(ss >> idx)
{
std::cerr <<"idx : " << idx << std::endl;
}
}
}
//std::string
}
fh.close();
return true;
}
图上的代码可以得到:
对于字符串idxs,使用ssidx,默认的是按照" “空格符分开的,使用getline,将其按照”/"来分割。然后使用std的类型转化函数。就可以获取相应的格式化输入。对于这个分割,可以按照格式去设置。
测试的结果,文件的格式如下:
文件的11行字符串进行格式化输入。它是有1/1是按照"/"进行分割。上面的代码可以输入的结果:
总结:以后尽量用"iostream"文件中的流函数进行格式化输入,希望对大家有帮助。