int printf(const char *buffer, ...); // Question.
'...' in C++.
In this particular example, the ellipsis means there are optional, follow-on arguments that can be passed.
You don't, because "..." is not C++. Using the dread ellipses construct "..." in C++ is punishable by death or just a beating handed to you by Fruny or Zahlman. If you want something like that you'll probably have to use streams.
Quote:
How do you make use of the '...' in functions? Printf uses it...
you try not to. this construct is rarley seen in c++.
but look up this, if you want to
it came first in a google for variadic functions
To be a little more informative: A function declared this way is called a "variadic" function. To make them work you need to do some work with some rather nasty macros (although it's not a very complicated process). Basically what happens is that all the things in that are passed get tossed onto the stack in order, regardless of their types or sizes, and it's up to the function to figure out how many things are there and what their types and sizes are. Since there isn't a reasonable way to do this in general, usually what these functions do is accept some information in the first argument (such as a printf-style 'format string') that is then interpreted to figure out what needs to go on.
As I'm sure you can imagine, this is tricky to get right, and it also can cause all kinds of undefined behaviour if the format string doesn't properly match the provided data (not to mention the annoyance of having to put it in in the first place, for those functions that *don't* format a string but just want extra arguments). It also just plain doesn't work with lots of C++ types - basically anything that isn't a POD type, because copy constructors aren't going to be invoked properly. Good luck dealing with references, too.
So yeah, as a rule of thumb, just don't freakin' do it, or even think about it. Set up some kind of streaming interface instead. If you do need printf-style formatted I/O (e.g. because you need "compound strings" for localization, where the order of outputted things might vary by language, and you don't want to have to recompile/change code to support it), you should take a look at boost::format.
As I'm sure you can imagine, this is tricky to get right, and it also can cause all kinds of undefined behaviour if the format string doesn't properly match the provided data (not to mention the annoyance of having to put it in in the first place, for those functions that *don't* format a string but just want extra arguments). It also just plain doesn't work with lots of C++ types - basically anything that isn't a POD type, because copy constructors aren't going to be invoked properly. Good luck dealing with references, too.
So yeah, as a rule of thumb, just don't freakin' do it, or even think about it. Set up some kind of streaming interface instead. If you do need printf-style formatted I/O (e.g. because you need "compound strings" for localization, where the order of outputted things might vary by language, and you don't want to have to recompile/change code to support it), you should take a look at boost::format.
This seems relevant (as found in several signatures):
"Basically whenever you invoke the dread ellipses construct you leave the happy world of type safety." -- SiCrane
It should not be used in c++, and only very carefully in c.
"Basically whenever you invoke the dread ellipses construct you leave the happy world of type safety." -- SiCrane
It should not be used in c++, and only very carefully in c.
read the above first... read it again....
Now, if you are still really curious, here's an example:
void logMessage( const char* szMessage, ... )
{
static I8 szBuffer[4097];
va_list list;
va_start( list, szMessage );
vsprintf( szBuffer, szMessage, list );
if (LogManager::InstancePtr())
LogManager::Instance().logMessage (szBuffer);
va_end( list );
}
Now, if you are still really curious, here's an example:
void logMessage( const char* szMessage, ... )
{
static I8 szBuffer[4097];
va_list list;
va_start( list, szMessage );
vsprintf( szBuffer, szMessage, list );
if (LogManager::InstancePtr())
LogManager::Instance().logMessage (szBuffer);
va_end( list );
}
Now now, the ellipses construct does have a place; so does goto. You just don't want to use it unless you're really, really sure you need it. In short, someone posting in 'For Beginners' with a question of the form 'How do you...?' is probably a good candidate for passing a linked list instead. :)
Quote:Original post by King of Men
Now now, the ellipses construct does have a place; so does goto. You just don't want to use it unless you're really, really sure you need it. In short, someone posting in 'For Beginners' with a question of the form 'How do you...?' is probably a good candidate for passing a linked list instead. :)
Huh?
Oh no no no, I'm not a beginner, definately not.
I have a templated doubly linked list with id's and iterators, and it's pretty good :).
Then, I have SDL/OpenGL graphics classes to handle sprites, text, stuff. I have an egine class, and event class, and so much more.
I just love being able to contribute to a thread without ever having posted in it. However...
Actually, what happens on most compilers is the the copy construction of the argument proceeds correctly. It's just that the destructor isn't called. So not only are you leaving the happy world of type safety, you also have a potential memory leak every time you call a function with the ellipses construct, because you may have accidently passed a class type to it. Though I have noticed on one occassion, that had horrible function pointer typecasting involved, the opposite happening: the copy constructor wasn't called and the destructor was called. However, I'm not sure that the ellipses had anything to do with that, since the code was basically a walking undefined behavior.
Quote:Original post by Zahlman
It also just plain doesn't work with lots of C++ types - basically anything that isn't a POD type, because copy constructors aren't going to be invoked properly.
Actually, what happens on most compilers is the the copy construction of the argument proceeds correctly. It's just that the destructor isn't called. So not only are you leaving the happy world of type safety, you also have a potential memory leak every time you call a function with the ellipses construct, because you may have accidently passed a class type to it. Though I have noticed on one occassion, that had horrible function pointer typecasting involved, the opposite happening: the copy constructor wasn't called and the destructor was called. However, I'm not sure that the ellipses had anything to do with that, since the code was basically a walking undefined behavior.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement