Can sprintf / formatted strings be passed directly to a function? - c++

Is something like this allowed in C++? If so, how do I do it?
myFunction("User input: %s", a);
Or is the only way to format it first and then pass it?

If you want to write a function that takes variable parameters, the answer is yes, and here's how you declare such a function:
void myFunction(const char*, ...);
Note the elipsis at the end.
But now that you know how to do this, I'll complicate things for you. You should not do this. The myFunction() declared above is type-unsafe, and completely sidesteps every means C++ has to protect you from mistakes.
There are other ways to accomplish something like this (vector comes to mind), but I have found that if you're needing a function that takes variable parameters, it's a code smell that indicates that there is somethign wrong with your design in the first place. Take a closer look at why you need this.
EDIT:
If what you're trying to do is not pass variable parameters per se, but a formatted string (like your OP says), then you would need to do the string formatting yourself in your function. There are ways to do this depending on your platform. In Windows, you'd probably use vsprintf() or something similar.
But again, if you need to do this, there are better ways. Personally I'm fond of using Boost format.

I guess what you want is to call a function like vsprintf from your myFunction - this way you can do the formatting inside of your function. Example:
void myFunction(const char *format, ...)
{
char buf[1024];
va_list arglist;
va_start( arglist, format );
vsprintf(buf,format,arglist);
va_end( arglist );
}

It's legal to do what you're doing, except:
sprintf's behavior is to apply formatting to a string. Outside of that function (and the printf family in general), your arguments here don't really 'mean' anything, because your function signature could look like this:
void myFunction(const char* str1, const char* str2);
But what it does is up to you.
If you want a string modified before passing it into some function, you will either have to modify it outside myFunction (via sprintf or whatever) or pass all your arguments in and call sprintf inside the function.

Yes, it's allowed. No, it is not a part of the standard library, so you have to implement it yourself.

It is possible using the vsprintf() function from the C library, and writing myFunction() as taking variable arguments.
However, the usual disclaimers regarding variable argument methods apply: it's very easy to introduce buffer overruns or segmentation violations this way. Some compilers allow you to declare myFunction() as "printf-like", so that you could get some degree of compile-time checking of the arguments, but that is not portable.

Related

Are the methods in the <cstring> applicable for string class too?

I've tried out using memcpy() method to strings but was getting a "no matching function call" although it works perfectly when I use an array of char[].
Can someone explain why?
www.cplusplus.com/reference/cstring/memcpy/
std::string is an object, not a contiguous array of bytes (which is what memcpy expects). std::string is not char*; std::string contains char* (somewhere really deep).
Although you can pull out the std::string inner byte array by using &str[0] (see note), I strongly encourage you not to. Almost anything you need to do already is implemented as a std::string method. Including appending, subtracting, transforming and anything that makes sense with a text object.
So yes, you can do something as stupid as:
std::string str (100,0);
memcpy(&str[0],"hello world", 11);
but you shouldn't.
Even if you do need memcpy behaviuor, try to use std::copy instead.
Note: this is often done with C functions that expects some buffer, while the developer wants to maintain a RAII style in his code. So he or she produces std::string object but passes it as C string. But if you do clean C++ code you don't need to.
Because there's no matching function call. You're trying to use C library functions with C++ types.

what does this "int logprintf( const char* ptr, ... )" do?

I have an old C++ code that has this line of code:
int logprintf( const char* ptr, ... );
and I am not sure what does it do exactly? should I change the code in order to be able to compile the code with new versions of the compiler?! does anybody have an idea? any help would be appreciated.
That's just C code and any compiler made since the 1980s should be able to handle it. The definition is of a varidic function, or "varargs" in C parlance.
What that does is declare a method signature, nothing more. Presumably somewhere else, either in a library you link in or in a C or C++ file you compile there's a matching implementation.
Most printf-style functions do not have a fixed number of arguments. This is what the ellipsis ... represents, zero or more arbitrary arguments go there.

c making variable argument required

I have a function as
AddSprintf(char* , ... )
I want to make compile time error if somebody is calling it without two arguments.
Currently if somebody is calling like
AddSprintf("hello")
it works. But I want to disable calling like this.
Is there any way using g++ I can force passing of argument ?
Overload AddSprintf:
void AddSprintf(const char* , ... ) {}
void AddSprintf(const char*);
Then you get a weird error message when compiling AddSprintf("hello")
But keep in mind that with C++11 you should use variadic templates because they are typesafe.
What about
AddSprintf(char* , char*, ... )
?
You can't, really. The dots stand for "zero or more arguments", and there is no way of knowing if there is any arguments. Except maybe using assembler and do some checking of the stack pointer.
As 0A0D says, it's variadic - by definition, the compiler is going to be fine with it. If you want it to fail at compiler time, you may have to pull tricks - for example, if you're unit testing, have code that makes the function fail with one argument call, so that new programmers will know they can't do that.
That said, why are you trying to do this? There may be a better solution to your problem.
If you want to stick to the same name, then you can use variadic macro:
#define AddSprintf(X,...) AddSprintf(X,__VA_ARGS__)
But be very careful with this solution, as AddSprintf would work first as text replacement in preprocessing stage. Then only it would be a function.

Variable arguments weirdness

Ok, so this piece of code works fine in the Debug but not in Release build.
int AddString(LPCTSTR lpszString, ...)
{
RArray<LPCTSTR> strings;
va_list args;
va_start(args, lpszString);
do
{
strings.Add(lpszString);
} while (lpszString = va_arg(args, LPCTSTR));
va_end(args);
// ... rest of code ...
}
It seems in Release, va_arg just returns an extra value containing rubbish. So if I pass on 3 parameters: I fetch 3 in Debug and miraculously 4 in Release... How is this possible? Using VS2010 btw.
(RArray is just a simple template class comparable to MFC's CArray, does not influence results)
Thanks!
Edit: I call it like this
AddString(_T("Hello, world!"), _T("Hallo, wereld!"), _T("Hallo, Welt!"));
You're doing it the wrong way and you're just lucky with the debug build.
Notice that va_arg does not determine either whether the retrieved argument
is the last argument passed to the function (or even if it is an element
past the end of that list). The function should be designed in such a way
that the amount of parameters can be inferred in some way by the values of
either the named parameters or the additional arguments already read.
Supply either the length of the list in an integer or pass a NULL at the end of the list.
You're not supplying the final NULL argument your function expects. You have to do this yourself at the point where you call AddString:
AddString(_T("Hello, world!"), _T("Hallo, wereld!"), _T("Hallo, Welt!"), NULL);
It is likely that the debug build zeros out some memory that the release build doesn't. This could explain why your code works in debug but not in release.
Also, you might want to convert the do {} while (...) loop into while (...) {}, to make sure your code doesn't malfunction if no optional arguments are given.
va_arg does not offer any guarantee to return 0 after last real argument.
If you're going to use the C style variable arguments, then you need to establish some way of determining the number of arguments, e.g. a count or a terminating zero.
For example, printf determines the arguments from the format specification argument.
In C++ you can often, instead, use chained calls, such as the operator<< calls used for standard iostreams.
The simple, basic idea is that the operator or function returns a reference to the object that it is called on, so that further operator or function calls can be appended.
Cheers,

c++ va_arg typecast issue

All,
I am writing a small c++ app and have been stumped by this issue. Is there a way to create (and later catch ) the error while accessing element from va_list macro using va_arg if element type is not expected. Eg:-
count=va_arg(argp,int);
if (count <= 0 || count > 30)
{
reportParamError(); return;
}
Now, if I am passing a typedef instead of int, I get garbage value on MS compiler but 95% of time count gets value 0 on gcc (on 64 bit sles10 sys). Is there a way I can enforce some typechecking, so that I get an error that can be caught in a catch block?
Any ideas on this would be very helpful to me. Or is there a better way to do this. The function prototype is:-
void process(App_Context * pActx, ...)
The function is called as
process(pAtctx,3,type1,type2,type3);
It is essential for pActx to be passed as 1st parameter and hence cannot pass count as 1st parameter.
Update-1
Ok, this sounds strange but nargs does not seem to part of va_list on sles10 gcc. I had to put in
#ifdef _WIN32
tempCount=va_arg(argp,int)
#endif
After using this, parameters following nargs do not get garbage values. However, this introduces compiler/platform based #ifdefs....Thanks Chris and Kristopher
If you know a count will always be passed as the second argument, then you could always change the signature to this:
void process(App_Context * pActx, int count, ...)
If that's not an option, then there is really no way to catch it. That's just how the variable-argument-list stuff works: there is no way for the callee to know what arguments are being passed, other than whatever information the caller passes.
If you look into how the va_arg macro and related macros are implemented, you may be able to figure out how to inspect all the stuff on the stack. However, this would not be portable, and it is not recommended except as a debugging aid.
You also might want to look into alternatives to variable-arguments, like function overloading, templates, or passing a vector or list of arguments.
No, there is no way. varargs doesn't provide any way to check the types of parameters passed in. You must only read them with the correct type which means that you need another way of communicating type information.
You are likely to be better off avoiding varargs functionality unless you really need it. It's only really a C++ feature for the sake of legacy functions such as printf and friends.