The online racing simulator
General C++ Related Questions
(21 posts, started )
General C++ Related Questions
Just a thread for people to ask and answer C++ related questions.

[As I'm stuck learning it (to benefit the community of course).]
Take a function like printf that accepts a variable number of arguments what I would like to do is pass these variable number of functions to a sub function without changing their order. An example of this would be aliasing the printf function to a function called console ...

#include <stdio.h>

void console(const char *_sFormat, ...);

int main () {
console("Hello World!");
return 0;
}

void console(const char *_sFormat, ...) {
printf("[APP] %s\n", _sFormat);
}

If I did for example console("Hello %s", sName);, I would want the name to be passed to the printf function also, but it has to be able to continue to accept a varable number of arguments like the printf already does.
#include <stdio.h>
#include <stdarg.h>

/**
* Prints to stdout as console.
*
* @param _sFormat The string and the format of the string to print & save.
* @parma ... Any Arguments.
* @return VOID
*/
void console(const char *_sFormat, ...) {
char sDest[256]; // In a console the max useful size is really 72.
// list of arguments.
va_list vaArgs;
// parse the list from the ellipsis ('...').
va_start(vaArgs, _sFormat);
// Save the formatted string into _sDest.
vsprintf(sDest, _sFormat, vaArgs);
// closes the argument list.
va_end(vaArgs);

printf("[APP] %s\n", sDest);
}

Yea it will most likely be using va_start and such as yankman stated.


void ConsoleFormat(const char *szFormat, ...)
{
static char szBuffer[1024];

va_list va;
va_start(va, szFormat);
vsprintf_s(szBuffer, szFormat, va);
va_end(va);
cout << [API] << szBuffer << '\n';
}

Note that this is poor since if the string and inputs exceed 1kb it _WILL_ crash because you will run out of space within szBuffer. I've never used this with special 'large' cases and in practice I've never had an issue.

EDIT: You beat me.
Quote from blackbird04217 :Note that this is poor since if the string and inputs exceed 1kb it _WILL_ crash because you will run out of space within szBuffer. I've never used this with special 'large' cases and in practice I've never had an issue.

Anyway to enforce the one kb limit, or have the make a varable of a varable size to accoidate any input the function might get. (I'd like to make all of the functions I use as bullet proof as possible, especially with me being new to the language it would be a real bitch to find out that my program was crashing because of some silly error I did on my first day of programming several years later, not to mention it being really hard to find.)

Quote from blackbird04217 :EDIT: You beat me.

Yeah, but only just . We posted in the same minute as well. .
Is there any particular reason you chose C++?
Quote from AndroidXP :Is there any particular reason you chose C++?

C++ is the native interface language for the PAWN programming language, and PAWN's Implementer's Guide is written with C++ examples, so I think it should be easier for me to get a PAWN / SmallC plugin interface going for InSim.
Quote from Dygear :Anyway to enforce the one kb limit, or have the make a varable of a varable size to accoidate any input the function might get. (I'd like to make all of the functions I use as bullet proof as possible, especially with me being new to the language it would be a real bitch to find out that my program was crashing because of some silly error I did on my first day of programming several years later, not to mention it being really hard to find.)

For that particular functionality you can never know how big a buffer will be. Consider the case; ConsoleFormat("Blah %s, %s", "String of unknown length", "another unknown"); so you will never know. Either choose a high number and watch what you send in or have some idea of what your doing.

If you knew the size you could use dynamic memory. 'new' / 'malloc' and remember to call 'delete' / 'free' respectively. However, starting out, I would use the fixed size array, and make a solid note of the assumption and possible failure. The dynamic allocation won't work in this situation because you don't know the size of buffer you would need. So again you're stuck to some number that could be too small.

Like I've said, I've used that function and never run out of room, but I know it has limits and I don't use that function for dumping lots of data.

----------------

The final option, which I've used before is to allow the "caller" to send in their own buffer:

ConsoleFormat(char *szBuffer, const char *szFormat, ...);

You could take in the bufferSize if needed as well, but this allows the caller to do something like.


char *pBigBuffer = new char[1024*1024*100]; //100mb buffer should be big enough for anything. Worry about running out of memory/slow allocation...
ConsoleFormat(pBigBuffer, "%s%s%s", codeDump, dataDump, logDump");
delete [] pBigBuffer;

that is obviously not reccomended but pretend all the 'dumps' are large character arrays that end with a null-terminator of course since printf %s requires that. But since they are large they might fill a really big space, and in this version of the function it is flexible enough to do that. You can't have both functions because of the ... -the compiler won't know which to call. You can rename it ConsoleFormat and ConsoleFormatBig.
In that case I'll set up the 1kB buffer I'm pretty sure I'm not going to be printing anything that comes close to that large.
If you want direct contact with me, for throwing questions at or whatever, PM me and I'll give you my Instant Messenger info.

My example was a little over the top, really you would need to call the 'big' function anytime you go over 1kb, though like I said, in common practice I've never hit that limit in years of coding like that - then again, it is also ony used in debug builds for me- getting completely removed in Release builds.
I wouldn´t use printf in a C++ program because it is less type safe than cout. This would be my solution to adding a prefix for every line:


#include <iostream>
#include <string>

using namespace std;

class Logger {
public:
Logger(ostream& os, string prefix = "[APP] ") : mOut(os), mPrefix(prefix) {}

ostream& log() {
return mOut << mPrefix;
}

private:
ostream& mOut;
string mPrefix;
};

int main() {
Logger l(cout);

l.log() << "Test" << endl;
l.log() << "Line 2";

return 0;
}

Quote from draugdel :I wouldn´t use printf in a C++ program because it is less type safe than cout. This would be my solution to adding a prefix for every line:

I'm just slightly worried about the readability of that code, granted I don't think there are going to be too many people looking at the source code besides me, but I'm considering a MIT license for this aswell. (But I might make it GPL v3 to make it more in line with the original spirit of AMX Mod.)
I''m not too familiar with open source licenses, though recently I've been trying to use open source projects to get better at analyzing code. Something one of the companies I applied to mentioned I should practice by looking at open source projects. Problem is I haven't got a single one to build properly, they all have dependencies and strange stuff out of the gate... Why can't you just get a project and go? -sorry for the rant. I was going to ask if anyone knew of a small resource that described in laymen terms the advantages/disadvantages/purposes of each license as 'general overlook' versus getting nitty and gritty. Not exactly C++ related but it was brought up in the thread.

Side note, where cout has type checking, I find printf much more readable and at times easier to use. I'm not saying you can't make mistakes though;


std::string strHello = "Hello";
char szHello[] = "Hello";

printf("char * = %s\n", szHello);
printf("string = %s\n", strHello); //BAD CODE
printf("string = %s\n", strHello.c_str()); //Good.

//OR the equivalent
cout << "char * = " << szHello << '\n';
cout << "string = " << strHello << '\n'; //works fine because string overloaded the << with iostream.
cout << "string = " << strHello.c_str() << '\n'; //also works

So where as you do have to be more careful there is nothing wrong with it. In my opinion if you are coding you need to be careful so this helps stay on your toes.
Quote from Dygear :
vsprintf(sDest, _sFormat, vaArgs);


I'm using this function so sDest has no chance of overflowing.

vsnprintf(sDest, sizeof(sDest) - 1, _sFormat, vaArgs);

God, I'm really taking my time with such a small function .

Quote from Dygear :
char sDest[256];


As I've allocated some memory, don't I also have to free it? Or is that only for memset / alloc calls, not definitions like this (I hope that's handled by the compiler for assigning and freeing memory in this fashion, or I just leaked some memory.)
Quote from blackbird04217 :Problem is I haven't got a single one to build properly, they all have dependencies and strange stuff out of the gate... Why can't you just get a project and go?

I don't have much C++ experience at all, but back when I tried to (and finally also succeeded in) getting the Jagged Alliance 2 sources to compile on VS2005, it was a huge pain in the butt to set everything up. There were a few type differences that VS wanted to have explicitly defined, which was relatively easy to fix and kinda understandable, but the random missing references, the need for special compiler flags and the completely cryptic and unhelpful linker errors made this endeavour quite an exercise in patience. And even after I got it running, debugging was kind of a bad joke.

I'm not sure what the point of this little anecdote was, but I guess "I had similar experiences and I feel with you" comes close. Naturally, I wouldn't touch C++ with a ten foot pole after that experience, and for what I do it is never the best choice of programming language anyway. Can't really see the point of using it for such high level stuff as InSim at all, but that's probably just me . Of course, if you (want to) work for a company that is stuck on C++ due to history (or maybe even has valid reasons to use it), then it can't be helped.


(Edit: Please ignore my ramblings, this is a C++ questions thread, not a "C++ vs. other languages" one. It's sometimes just kinda amusing to see how much time you have to waste on trivial functionality)
Quote from AndroidXP :(Edit: Please ignore my ramblings, this is a C++ questions thread, not a "C++ vs. other languages" one. It's sometimes just kinda amusing to see how much time you have to waste on trivial functionality)

Indeed brotha! I tried to get this to compile, but it seems C++ does not support variable char arrays.

The Errors
1>.\InSimMod.cpp(66) : error C2057: expected constant expression
1>.\InSimMod.cpp(66) : error C2466: cannot allocate an array of constant size 0
1>.\InSimMod.cpp(66) : error C2133: 'sDest' : unknown size
1>.\InSimMod.cpp(68) : error C2070: 'char []': illegal sizeof operand

Teh Code
void console(const char *_sFormat, ...) {
// Varable Defines
char* sArg;
int iSize = 0;
// list of arguments.
va_list(vaArgs);
// parse the list from the ellipsis ('...').
va_start(vaArgs, _sFormat);
// Length of Formatted String + NUL terminator
iSize = sizeof(_sFormat) + 1;
// While we still have more args ...
do {
// Get argument in place in char array (string).
sArg = va_arg(vaArgs, char*);
// Add the size of the string to iSize for a running total.
iSize += sizeof(sArg);
} while (sArg != NULL);
// Define our Desintation string.
char sDest[iSize];
// And write the information to the destination.
vsnprintf(sDest, sizeof(sDest) - 1, _sFormat, vaArgs);
// closes the argument list.
va_end(vaArgs);
printf("[ISM] %s\n", sDest);
}

That would be because iSize is not a constant, so the size of the array is unknown - todo that you would need dynamic memory, which for your current situation I advise to stick with 1024, or 2048 if needed... At least for now.
Quote from Dygear :
As I've allocated some memory, don't I also have to free it? Or is that only for memset / alloc calls, not definitions like this (I hope that's handled by the compiler for assigning and freeing memory in this fashion, or I just leaked some memory.)

If you allocate memory on the heap you need to free it afterwards.

char sDest[666]; // this is put on the stack, the compiler knows the size at compile time.

char* psDest;
psDest = new char[666]; // this is put on to the heap so you have to free it afterwards
delete [] psDest;

psDest = 0; // good programming practise to set the pointer to zero

For the buffer problem it would be safe to allocate the desired buffer size,
and strncpy to fill the buffer.

In general you should stick to stl c++ container classes they have bullet proof memory management integrated.

Edit: Didn't see you were already using vsnprintf.
Quote from yankman :
In general you should stick to stl c++ container classes they have bullet proof memory management integrated.

Just started reading this nice thread and that right there is the best statement I've heard yet. Allocating static character arrays, printf stuff, malloc, etc are all very low level and mostly C and not the newer, safer, dynamic STL classes that are in C++. printf is nice and "simple" but you might regret it later. Memory leaks anyone?

http://www.parashift.com/c++-f ... nput-output.html#faq-15.1
http://stackoverflow.com/quest ... -printf-for-faster-output
And the string class was born.

Edit: and no memory management is bullet-proof.

General C++ Related Questions
(21 posts, started )
FGED GREDG RDFGDR GSFDG