Sign in to follow this  
Niux

sscanf_s in linux (ubuntu)

Recommended Posts

Hey all To keep this short; I'm fairy new to C/C++ and I got this simple .OBJ loader which uses sscanf_s however I cannot compile the code. I've googled arroud, but cannot seem to find a solution to my problem. Can anyone tell me what the problem is (?) - is there a header I haven't included or ? EDIT: Error below, highlighted the use of sscanf_s Here's the code:
#include "SimpleOBJ.h"
#include <string>
#include <fstream>
#include <iostream>


void loadModel( const std::string filename, TriangleMesh &mesh )
{
	std::ifstream in(filename.c_str());

	if(!in.good())
	{
		cout  << "ERROR: loading obj:(" << filename << ") file is not good" << "\n";
		exit(0);
	}

	char buffer[256], str[255];
	float f1,f2,f3;

	while(!in.getline(buffer,255).eof())
	{
		buffer[255]='\0';

		sscanf_s(buffer,"%s",str,255);

		// reading a vertex
		if (buffer[0]=='v' && (buffer[1]==' '  || buffer[1]==32) )
		{
			if ( sscanf(buffer,"v %f %f %f",&f1,&f2,&f3)==3)
			{
				mesh.verts.push_back(make_float3(f1,f2,f3));
			}
			else
			{
				cout << "ERROR: vertex not in wanted format in OBJLoader" << "\n";
				exit(-1);
			}
		}

		// reading a vertex normal
		else if (buffer[0]=='v' && buffer[1]=='n')
		{
			if( sscanf_s(buffer,"vn %f %f %f",&f1, &f2, &f3)==3)
			{
				mesh.normals.push_back(make_float3(f1,f2,f3));
			}
			else
			{
				cerr << "ERROR: vertex normal not in wanted format in OBJLoader" << endl;
				cerr << buffer << endl;
				exit(-1);
			}
		}

		// reading FaceMtls 
		else if (buffer[0]=='f' && (buffer[1]==' ' || buffer[1]==32) )
		{
			TriangleFace f;

			int nt = sscanf(buffer,"f %d/%d/%d %d/%d/%d %d/%d/%d ",&f.v[0],&f.vt[0],&(f.vn[0]),&f.v[1],&f.vt[1],&(f.vn[1]),&f.v[2],&f.vt[2],&(f.vn[2]));
			if (nt!=9)
			{
				nt = sscanf(buffer,"f %d/%d %d/%d %d/%d ",&f.v[0],&f.vn[0],&f.v[1],&f.vn[1],&f.v[2],&f.vn[2]);
				if(nt == 1)
				{
					nt = sscanf(buffer,"f %d//%d %d//%d %d//%d ",&f.v[0],&f.vn[0],&f.v[1],&f.vn[1],&f.v[2],&f.vn[2]);
				}

				if (nt!=6)
				{
					nt = sscanf(buffer,"f %d %d %d",&f.v[0],&f.v[1],&f.v[2]);
					if( nt!=3 )
					{
						cout << "ERROR: I don't know the format of that FaceMtl" << "\n";
						exit(-1);
					}
				}
			}


			mesh.faces.push_back(f);
		}
	}

	// calculate the bounding box
	mesh.bounding_box[0] = make_float3(1000000,1000000,1000000);
	mesh.bounding_box[1] = make_float3(-1000000,-1000000,-1000000);
	for(unsigned int i = 0; i < mesh.verts.size(); i++)
	{
		//update min value
		mesh.bounding_box[0].x = min(mesh.verts[i].x,mesh.bounding_box[0].x);
		mesh.bounding_box[0].y = min(mesh.verts[i].y,mesh.bounding_box[0].y);
		mesh.bounding_box[0].z = min(mesh.verts[i].z,mesh.bounding_box[0].z);

		//update max value
		mesh.bounding_box[1].x = max(mesh.verts[i].x,mesh.bounding_box[1].x);
		mesh.bounding_box[1].y = max(mesh.verts[i].y,mesh.bounding_box[1].y);
		mesh.bounding_box[1].z = max(mesh.verts[i].z,mesh.bounding_box[1].z);

	}

	if(mesh.normals.size()>0)
		mesh.has_normals = true;
	else
		mesh.has_normals = false;

	cout << "obj file loaded: number of faces:" << mesh.faces.size() << " number of vertices:" << mesh.verts.size() << endl;
	cout << "obj bounding box: min:(" << mesh.bounding_box[0].x << "," << mesh.bounding_box[0].y << "," << mesh.bounding_box[0].z <<") max:" 
		<< mesh.bounding_box[1].x << "," << mesh.bounding_box[1].y << "," << mesh.bounding_box[1].z <<")" << endl;

}
Here's the compile error:
Building file: ../src/simpleOBJ.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/simpleOBJ.d" -MT"src/simpleOBJ.d" -o"src/simpleOBJ.o" "../src/simpleOBJ.cpp"
../src/simpleOBJ.cpp: In function ‘void loadModel(std::string, TriangleMesh&)’:
../src/simpleOBJ.cpp:29: error: ‘sscanf_s’ was not declared in this scope
make: *** [src/simpleOBJ.o] Error 1
GCC version: gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9)

Share this post


Link to post
Share on other sites
Ah okay. Thank you!

Now I get a warning form the line

sscanf_s(buffer,"%s",str,255);


warning:

../src/simpleOBJ.cpp:29: warning: too many arguments for format

Share this post


Link to post
Share on other sites
Ah, my bad. sscanf_s is not a like-for-like replacement for sscanf.

For example if you have "%s" in your format string, you have to pass both the buffer-pointer and the length of the buffer as arguments to sscanf_s, but only the pointer to sscanf.

There's more information via that page I linked to.

So you have a handful of options:

1. Just use sscanf everywhere carefully. In particular, make use of the ability to specify buffer sizes within the format string itself.

2. Write a read_string() function that internally uses sscanf or sscanf_s, depending on the platform.

3. Re-write to use C++ iostreams and std::strings, making overflow impossible by construction.

Personally, I'd go with 1.

Share this post


Link to post
Share on other sites
the *scanf and *printf functions are legacy C functions present in the C++ standard library because backwards compability is required. While frequently used in tutorials and by many old C programmers who have moved on to C++, I would generally discourage their use in new code. Functions based on format strings and variable argument lists are known to be prone to mistakes and security issues. Although working with the "pure" C++ iostreams, strings and stringstreams may seem tedious at first, you will find that you code is cleaner, more secure and less of a security risk.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this