LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-20-2008, 03:25 PM   #1
Ephracis
Senior Member
 
Registered: Sep 2004
Location: Sweden
Distribution: Ubuntu, Debian
Posts: 1,109

Rep: Reputation: 50
C++ - stdarg.h: use ... as an argument


Code:
#include <stdio.h>
#include <stdarg.h>

void function1(const char *txt, ...)
{
    printf("FUNC1: ");

    va_list ap;
    va_start(ap, txt);
    vprintf(txt, ap);

    va_end(ap);
}

void function2(const char *txt, ...)
{
    printf("FUNC2: ");

    va_list ap;
    va_start(ap, txt);
    vprintf(txt, ap);

    /* here comes the tricky part */
    function1(txt, ???);

    va_end(ap);
}

int main()
{
    function1("Message #1\n");
    function2("Message #2\n");
    
    return 0;
}
The output I want is:
Quote:
FUNC1: Message #1
FUNC2: Message #2
FUNC1: Message #2
Pretty simple.
 
Old 02-20-2008, 05:44 PM   #2
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
You can't do it from within the function unless you define a variant to function1 taking a va_list argument. You can use a macro to fake it, though:
Code:
#include <stdio.h>
#include <stdarg.h>

void function1(const char *txt, ...)
{
    printf("FUNC1: ");

    va_list ap;
    va_start(ap, txt);
    vprintf(txt, ap);

    va_end(ap);
}

void __function2(const char *txt, ...)
{
    printf("FUNC2: ");

    va_list ap;
    va_start(ap, txt);
    vprintf(txt, ap);

    va_end(ap);
}

#define function2(args ...) { __function2(args); function1(args); }

int main()
{
    function1("Message #1: %s\n", "hello");
    function2("Message #2: %s\n", "goodbye");

    return 0;
}
ta0kira
 
Old 02-21-2008, 04:50 AM   #3
Ephracis
Senior Member
 
Registered: Sep 2004
Location: Sweden
Distribution: Ubuntu, Debian
Posts: 1,109

Original Poster
Rep: Reputation: 50
Ok..

I am not very good with preprocessor-thingys. So how would I use this when function1 and function2 (and __function2) are all in the same class?
 
Old 02-21-2008, 11:50 AM   #4
excel28
Member
 
Registered: Jun 2003
Location: California
Distribution: Slackware
Posts: 72

Rep: Reputation: 15
I had a similar thing I wanted to in the past. And here was my answer... My function only did string formatting, so I just had to format the string, and pass it to the other function and continue on.

Code:
void logIt(const char* s, ...)
{
   va_list va_args;
   va_start(va_args, s);

   char sz[MAX];

   _vsnprintf(sz, MAX, s, va_args);

   // do something... 
   printf("Log: %s\n", sz); // I'll just print it...
}

void send(const char* s, ...)
{
   va_list va_args;
   va_start(va_args, s);

   char sz[MAX];

   _vsnprintf(sz, MAX, s, va_args);

   // at this point, sz is the formatted string

   logIt(sz); // this will just send the formatted string as is...

   // this will send another formatted string and one of the 
   //params is the formated one we just did
   logIt("MyObject::send - %s", sz); 

   // do something...
   SendToNetwork(sz);
}
 
Old 02-21-2008, 01:19 PM   #5
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
OOO dear me dreaded va_args!!
Please explain what it is you are trying to do and I will attempt to show you a C++ version which does not loose type safety.
 
Old 02-22-2008, 02:39 AM   #6
Ephracis
Senior Member
 
Registered: Sep 2004
Location: Sweden
Distribution: Ubuntu, Debian
Posts: 1,109

Original Poster
Rep: Reputation: 50
Quote:
Originally Posted by dmail View Post
OOO dear me dreaded va_args!!
Please explain what it is you are trying to do and I will attempt to show you a C++ version which does not loose type safety.
I am building an internal message system (for logging, output, etc). And I want to use printf-style formatting.
 
Old 02-22-2008, 05:02 AM   #7
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
Can I ask why you want to use printf formatting?

Here is some code for you that uses insertion operators, the same could be done by redirecting std::cout or by using std::log

Code:
///////////////////////////////////////////////////////////////////////////////
///  Log.h
///  Logger class which uses stringstreams.
///  @remarks To end a line either log_instance.flush() can be called or the
///  class public member endl can be pushed into the stream.
///  @author Liam Devine  @date 25/10/2006
///////////////////////////////////////////////////////////////////////////////
#ifndef LOGGER_H_
#	define LOGGER_H_


#	include <iostream>
#	include <fstream>
#	include <sstream>
#	include <ctime>
#	include <string>
#	include <stdexcept>





//disable depreciated warnings for asctime and localtime
#	if( defined(_MSC_VER) && (_MSC_VER >= 1400) )
#			pragma warning( push )
#			pragma warning (disable :4996)
#	endif//_MSC_VER >=1400

#	define FILENLINE "File:" <<__FILE__ " Line:" << __LINE__ <<" "

namespace LVD
{
	///  Log
	///  Log class which logs to the file specified in the constructor
	class Log
	{
	public:

		///  An empty structure for determining an end of line
                struct Nulltype{};
		Nulltype endl;
		
		Log(std::string log_file = "log_file.txt",bool append = false):m_send_to_console(false), m_log_file(log_file)
		{ 
			if( !append)m_log.open(m_log_file.c_str(), std::ios::out );
			else m_log.open(m_log_file.c_str(), std::ios::out | std::ios::app);

			if( ! m_log.is_open()  )
			{throw(std::runtime_error("Can not open log file."));}

			time_t start_time;
			time ( &start_time );

			m_log <<std::endl <<"LOG STARTED: " << asctime ( localtime ( &start_time ) )
				<<std::endl <<std::flush;
		}
		~Log()
		{
			if( m_log.is_open() )
			{ 
				time_t end_time;
				time ( &end_time );

				m_log <<std::endl <<"LOG CLOSED: " <<asctime ( localtime ( &end_time ) )
					<<std::endl <<std::flush;
				m_log.close(); 
			}

		}

		///stream insertion operators
		template<typename T> 
			Log& operator <<(T const & t){m_msg <<t; return *this;}

		Log& operator <<(Nulltype const &/*t*/){flush(); return *this;}

			void flush()
			{
				m_log <<m_msg.str() <<std::endl;//endline will flush

				// Write to console if it's turned on
				if ( m_send_to_console )
				{
					std::cout << m_msg.str() << std::endl;
				}

				m_msg.str("");//clear the stream
			}

			// Sending true turns on writing to console (cout)
			void console_write( bool on ){ m_send_to_console = on; }
			bool console_write() const{ return m_send_to_console; }

	private:
		bool m_send_to_console;
		Log(Log const &);
		Log& operator = (Log const &);
		std::stringstream m_msg;
		std::string m_log_file;
		std::ofstream m_log;
	};

}


//enable depreciated warnings again after disabling for asctime and localtime
#	if( defined(_MSC_VER) && (_MSC_VER >= 1400) )
#			pragma warning (pop)
#	endif//_MSC_VER >=1400

Last edited by dmail; 02-22-2008 at 05:06 AM.
 
Old 02-22-2008, 08:38 AM   #8
Ephracis
Senior Member
 
Registered: Sep 2004
Location: Sweden
Distribution: Ubuntu, Debian
Posts: 1,109

Original Poster
Rep: Reputation: 50
Quote:
Originally Posted by dmail View Post
Can I ask why you want to use printf formatting?
Cause I really don't like the C++ way with << and stuff. It looks ugly and it is not as elegant and short as the printf-style. I just prefer the old ways.
 
Old 02-22-2008, 10:25 AM   #9
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by Ephracis View Post
I am building an internal message system (for logging, output, etc). And I want to use printf-style formatting.
I had almost the exact same question for almost the exact same problem several months ago. What I did was have the logging function take a const char*, then several "log message" functions (based on the event) that would take certain arguments based on the message, would snprintf them, then use the log function on that string. It works very well and has the added benefit of centralizing log messages, which allows you to have translations of your program.
ta0kira


Edit: an example:
Code:
#include <stdio.h>
#include <unistd.h>


//main logging function
void main_log(const char *mMessage)
{ printf("%s\n", mMessage); }


//in a translation source
void log_program_start(const char *nName, pid_t pProcess)
{
    char buffer[256];
    snprintf(buffer, 256, "program '%s' started (pid %i)", nName, pProcess);
    main_log(buffer);
}


//program
int main(int argc, char *argv[])
{
    log_program_start(argv[0], getpid());
    return 0;
}
The main logging functions I use add a lot more info, though, like time and pid automatically. This also lets you design a library with no specific logging format and have the using program define its own logging function.

Last edited by ta0kira; 02-22-2008 at 10:42 AM.
 
Old 02-22-2008, 11:01 AM   #10
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 78
You can also use boost::format() for this sort of thing.
 
Old 02-22-2008, 01:29 PM   #11
Ephracis
Senior Member
 
Registered: Sep 2004
Location: Sweden
Distribution: Ubuntu, Debian
Posts: 1,109

Original Poster
Rep: Reputation: 50
Quote:
Originally Posted by osor View Post
You can also use boost::format() for this sort of thing.
Problem there is that it would be another dependency. :P

Anyway, the thing I did was just to use two function inside the main class:

Quote:
void MainClass::message(const char *area, const char *txt, va_list ap)
{
// send output to logfile, stdout/stderr and GUI.
}

void MainClass::message(const char *area, const char *txt, ...)
{
va_list ap;
va_start(ap, txt);
message(area, txt, ap);
va_end(ap);
}
Then in other classes I would use just one function
Quote:
void AnotherClass::message(const char *txt, ...)
{
va_list ap;
va_start(ap, txt);
m_parent->message("Another Class", txt, ap);
va_end(ap);
}
With this setup I can do exactly what I wanted to: I can use printf-like logging from both the main class and the rest of the children. Just do something like:

message("Main Class", "Could not open %s", filename);
or
message("There was no errors");

And the message would be sent to the logfile, stdout/err or the GUI depending on the current settings. Where all stuff like timestamping, formatting, setting lower case or capitalize, handling multiliners, etc is done in only one place for the whole project.

It's wonderful, and it works. And in the Qt GUI I can use QString::vsprintf(), just hoping there's something as good available in GTK for when I'm gonna write the GTK GUI.

 
Old 02-22-2008, 01:48 PM   #12
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 78
Quote:
Originally Posted by Ephracis View Post
Problem there is that it would be another dependency.
Since the majority of boost is done entirely in headers, it would be only a compile-time dependency (i.e., it would not be a runtime dependency).
 
Old 02-22-2008, 02:17 PM   #13
Ephracis
Senior Member
 
Registered: Sep 2004
Location: Sweden
Distribution: Ubuntu, Debian
Posts: 1,109

Original Poster
Rep: Reputation: 50
Quote:
Originally Posted by osor View Post
Since the majority of boost is done entirely in headers, it would be only a compile-time dependency (i.e., it would not be a runtime dependency).
Wow, I did not know that.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
stdarg question shakezilla Programming 4 02-02-2008 10:41 AM
message sending failed : Error[22 ] invalid argument .....but each and every argument rakeshranjanjha Linux - Software 2 01-07-2008 11:22 PM
[SOLVED] varargs.h -> stdarg.h kaz2100 Programming 2 04-25-2006 07:54 AM
What the heck... Problems with stdarg? Cannot put out float figures. Zacharias Programming 3 08-07-2004 09:03 PM
stdarg with varaible amout of string jetfreggel Programming 11 01-06-2003 05:06 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:15 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration