LinuxQuestions.org
Share your knowledge at the LQ Wiki.
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 04-07-2008, 05:13 PM   #1
R00ts
Member
 
Registered: Mar 2004
Location: Austin TX, USA
Distribution: Ubuntu 11.10, Fedora 16
Posts: 547

Rep: Reputation: 30
Efficient use of C string libraries with C++ strings?


I have some...odd constraints on a project that I am working on. I'm not allowed to use C++ I/O (ie streams with the << and >> operator), but I am allowed to use C++ strings. I have a moderately complex logging manager class that accepts a printf-style formatted string and argument list, prints the string to a char buffer, then uses that buffer to construct a C++ string (which is later used to do some more complex string parsing operations that I didn't want to write using C strings). Here's the function in question:

Code:
void tLogManager::Message(eLogVerbosity level, const char* message, ...)
{
   if (level > _verbose_threshold || message == NULL)
   {
      return;
   }

   va_list arg_list;
   va_start(arg_list, message);
   
   // Use vsnprintf to get the size of the string as it would be rendered
   int string_length = vsnprintf(NULL, 0, message, arg_list);
   if (string_length <= 0)
   {
      Warning(__FILE__, __LINE__, "invalid formatted string: %s\n", message);
   }
   string_length++;
   
   // Now use vsnprintf to construct the string
   char* buffer = reinterpret_cast<char*>(malloc(sizeof(char) * string_length));
   if (buffer == NULL)
   {
      Warning(__FILE__, __LINE__, "could not create temporary buffer for string\n");
   }
   if (vsnprintf(buffer, string_length, message, arg_list) < 0)
   {
      va_end(arg_list);
      Warning(__FILE__, __LINE__, "invalid formatted string: %s\n", message);
      return;
   }
   va_end(arg_list);

   string msg_string(buffer);
   
   // This loop examines the entire string to make sure that all non-empty lines of text are
   // preceeded with "# ". The message string may contain multiple lines of text that are
   // separated by newline characters in the string
   _ParseMessageString(msg_string);

   printf("%s", msg_string.c_str());
   if (_IsLogFileOpen())
   {
      fprintf(_log_file, "%s", msg_string.c_str());
   }
   free(buffer);
}

This code works. What I really don't like about it though is that I allocate double the amount of memory for the string than I need (once for the char buffer, a second time when constructing the C++ string). I tried to circumvent this by removing the char buffer and instead trying to use the C++ string exclusively, but it didn't work correctly (my parsing code detected two newline characters for a string instead of one). Plus it just didn't seem very safe to me, since I had to const_cast the return value of msg_string.c_str() so that the second call to vsnprintf could accept the char pointer.


Anyway I'm not sure if I'll find any answers here (or if there even is an answer) to how to do this in a more optimal way. Just looking to see if anyone had any insights on how this could be done better. Thanks
 
Old 04-07-2008, 08:05 PM   #2
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
If you have more than one new line character then have you thought of using a different container like a vector?

Code:
std::vector<char> v(string_length);

....
 if (vsnprintf(&v[0], string_length, message, arg_list) < 0)
...
 
Old 04-08-2008, 10:09 AM   #3
R00ts
Member
 
Registered: Mar 2004
Location: Austin TX, USA
Distribution: Ubuntu 11.10, Fedora 16
Posts: 547

Original Poster
Rep: Reputation: 30
Yeah, I guess using a vector would be a bit cleaner since I don't have to do a malloc/free on a char pointer, but it still doesn't solve my larger problem of allocating double the amount of memory for the string that is needed. (I have to use C++ strings in this function no matter what, because the parsing code uses C++ string methods to manipulate the characters).
 
Old 04-08-2008, 11:02 AM   #4
dmail
Member
 
Registered: Oct 2005
Posts: 970

Rep: Reputation: Disabled
Maybe I am missing something but can you explain why
Quote:
"I tried to circumvent this by removing the char buffer and instead trying to use the C++ string exclusively, but it didn't work correctly (my parsing code detected two newline characters for a string instead of one)...
Quote:
"... Plus it just didn't seem very safe to me, since I had to const_cast the return value of msg_string.c_str() so that the second call to vsnprintf could accept the char pointer."
This is not correct you can use the index operator with returns a reference and take the address which is the address of the original char.

Code:
void tLogManager::Message(eLogVerbosity level, const char* message, ...)
{
   if (level > _verbose_threshold || message == NULL)
   {
      return;
   }

   va_list arg_list;
   va_start(arg_list, message);
   
   // Use vsnprintf to get the size of the string as it would be rendered
   int string_length = vsnprintf(NULL, 0, message, arg_list);
   if (string_length <= 0)
   {
      Warning(__FILE__, __LINE__, "invalid formatted string: %s\n", message);
   }
   string_length++;
   
   // Now use vsnprintf to construct the string
   std::string buffer;
   buffer.resize(string_length);

   if (vsnprintf(&buffer[0], string_length, message, arg_list) < 0)
   {
      va_end(arg_list);
      Warning(__FILE__, __LINE__, "invalid formatted string: %s\n", message);
      return;
   }
   va_end(arg_list);
   
   // This loop examines the entire string to make sure that all non-empty lines of text are
   // preceeded with "# ". The message string may contain multiple lines of text that are
   // separated by newline characters in the string
   _ParseMessageString(buffer);

   printf("%s", buffer.c_str());
   if (_IsLogFileOpen())
   {
      fprintf(_log_file, "%s", buffer.c_str());
   }
}
[edit]
And out of curiosity why can you not use streams?

Last edited by dmail; 04-08-2008 at 11:07 AM.
 
Old 04-08-2008, 11:43 AM   #5
R00ts
Member
 
Registered: Mar 2004
Location: Austin TX, USA
Distribution: Ubuntu 11.10, Fedora 16
Posts: 547

Original Poster
Rep: Reputation: 30
Ohhhh, now I see where you were going with this. I forgot that you can use indexing on strings to gain access to the characters. Alright, cool I think that solves my problems.


As for why I can't use streams: I think they are just being dumb. My group does a lot of driver development and I think they said something about streams not working correctly or something, but even then I'm developing a user application, and none of this code will be run in kernel space. I don't think they have very good reasons honestly other than "that's the way we've always done it", but I'm still relatively new here and I have to pass code reviews, so I must submit.


Thanks for your help!
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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
Need to search all files for string - strings command? jmur Programming 4 03-28-2008 02:35 PM
How to concatenate two strings into one string in B-shell? jimmyjiang Red Hat 5 01-08-2008 01:15 PM
Shell Script: Delete lines til string found or until particular string. bhargav_crd Linux - General 3 12-20-2007 11:14 PM
C: storing string which is more efficient. debiant Programming 22 09-01-2006 12:39 AM
how to find duplicate strings in vertical column of strings markhod Programming 7 11-02-2005 04:04 AM

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

All times are GMT -5. The time now is 04:28 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