c++ passing string to varargs - c++

#define LOG(format,...) Logger::Log(format,__VA_ARGS__)
#define STRIP(netIp) GeneralUtils::inet_ntop_(netIp)
string GeneralUtils::inet_ntop_(unsigned int netIp){
char strIP[INET_ADDRSTRLEN];
in_addr sin_addr;
sin_addr.s_addr = netIp;
inet_ntop(AF_INET, &sin_addr.s_addr, strIP, sizeof strIP);
return string(strIP);
}
when calling to :
LOG("src %s dst %s" ,STRIP(src_ip_));
i get compilation error:
cannot pass objects of non-trivially-copyable type ‘std::string {aka struct std::basic_string<char>}’ through ‘...’
I understand that varargs is c compatible , so i cannot send string to it.
Is there a simple way to bypass it?
Will it be correct to fix it like this:
#define STRIP(netIp) GeneralUtils::inet_ntop_(netIp).data()

You can pass const char * instead of std::string. You can take it from std::string by calling c_str()

#define STRIP(netIp) GeneralUtils::inet_ntop_(netIp).data()
is wrong, it will invoke undefined behavior since it doesn't include a terminating zero. Use
#define STRIP(netIp) GeneralUtils::inet_ntop_(netIp).c_str()
instead.

Related

passing literal string as const char * parameter causes code analyzer error

I have overloaded function
int put_message(int level, int sys_log_level, const char * inp_message);
int put_message(int level, int sys_log_level, const std::string &inp_message);
and call this function
put_message(0, LOG_ERR, "clock_gettime error");
Code is compiled and works
but Eclipse CDT Code analyzer says
Invalid arguments '
Candidates are:
int put_message(int, int, const char *)
int put_message(int, int, const ? &)
'
How can I fix this the error?
Update:
After modifying LOG_ERR to int(LOG_ERR) error disappears.
I have not add the in the header.
Adding solves the problem.
you are missing #include <string> or something related to string class
You need to cast the string to the correct type, the compiler treats "some string" as char[] so you need to cast it to const char*
Try with
put_message(0, LOG_ERR, (const char*)"clock_gettime error");

C++ cannot convert unsigned char to char* when calling my function

In this program I use the function gethostname to get the hostname of the server. However when running this below:
#include <sys/types.h>
#include <sys/socket.h>
⋮
int rc;
int server_sock;
u_char hostname[50];
⋮
rc = gethostname(&hostname,sizeof(hostname));
printf("hostname = %s\n",hostname);
I get the error:
Cannot convert u_char(*)[50] to char* for argument '1' to 'int gethostname(char*, size_t)'
You have an array of the wrong type (u_char instead of char) and you're passing a pointer to the array rather than passing it directly - &hostname is of type u_char(*)[50] - you want just a pointer, which would be just hostname:
The correct approach would be:
char hostname[50];
⋮
rc = gethostname(hostname,sizeof(hostname));

Macro expansion within a macro

I'm trying to create LOGDEBUG macro:
#ifdef DEBUG
#define DEBUG_TEST 1
#else
#define DEBUG_TEST 0
#endif
#define LOGDEBUG(...) do { if (DEBUG_TEST) syslog(LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), __VA_ARGS__); } while (0)
...
size_t haystack_len = fminl(max_haystack_len, strlen(haystack_start));
LOGDEBUG(("haystack_len %ld\n", haystack_len));
I am not using # or ## parameters to stringify the arguments, and yet g++ apparently tries to stringify them:
numexpr/interpreter.cpp:534:5: error: invalid conversion from ‘size_t {aka long unsigned int}’ to ‘const char*’ [-fpermissive]
Note that haystack_len is size_t and I do not convert it to char* in the macro, yet compiler sees it as such. Does g++ implicitly tries to convert macro arguments to strings?
How to fix that? I mean, I'm using gnu LOG_MAKEPRI macro for syslogging, is it this macro that may be causing trouble? Also, is there some way to see the macro-expanded code?
How to fix that?
LOGDEBUG(("haystack_len %ld\n", haystack_len)); call the macro with one unique argument.
So it will produce:
do { if (DEBUG_TEST) syslog(LOG_MAKEPRI(LOG_SYSLOG, LOG_DEBUG), ("haystack_len %ld\n", haystack_len)); } while (0);
And ("haystack_len %ld\n", haystack_len) use comma operator and result in haystack_len
So you have to call it that way: LOGDEBUG("haystack_len %ld\n", haystack_len);
Also, is there some way to see the macro-expanded code?
gcc -E may help.

strrchr causing 'Cannot convert from const char * to char *'

I am trying to compile some code that was given to me that I'm told compiles fine. Perhaps on a different compiler. I am using VS2010 and I have the following line:
char *dot = strrchr(filename, '.');
This causes the compiler error:
"error C2440: 'initializing': cannot convert from 'const char *' to
'char *'
How come? And how do I fix it?
The error message is pretty clear. strrchr returns a const char*. So you need:
const char *dot = strrchr(filename, '.');
If you really need a char*, you can use strcpy for conversion.
C++ has saner versions of strchr and strrchr than C thanks to overloading, so say:
const char * dot = strrchr(filename, '.');
In C, which has no overloading, you only have a single function char * strrchar(const char *, const char *), and it's up to you to decide whether the result is constant or mutable, depending on which type of pointer to feed into the function. C has many such type-unsafe functions.

Library redefines NULL

I'm working with a library that redefines NULL. It causes some problems with other parts of my program. I'm not sure what I can do about it. Any idea? My program's in C++, the library's in C.
#ifdef NULL
#undef NULL
#endif
/**
* NULL define.
*/
#define NULL ((void *) 0)
Oh, and it produces these errors:
Generic.h:67: error: default argument for parameter of type 'LCD::LCDBase*' has type 'void*'
Generic.cpp: In constructor 'LCD::Generic::Generic(std::string, Json::Value*, int, LCD::LCDBase*)':
Generic.cpp:44: error: invalid conversion from 'void*' to 'QObject*'
Generic.cpp:44: error: initializing argument 2 of 'LCD::LCDWrapper::LCDWrapper(LCD::LCDInterface*, QObject*)'
Generic.cpp: In member function 'void LCD::Generic::BuildLayouts()':
Generic.cpp:202: error: invalid conversion from 'void*' to 'LCD::Widget*'
Generic.cpp: In member function 'void LCD::Generic::AddWidget(std::string, unsigned int, unsigned int, std::string)':
Generic.cpp:459: error: invalid conversion from 'void*' to 'LCD::Widget*'
scons: *** [Generic.o] Error 1
Here's the first one:
Generic(std::string name, Json::Value *config, int type, LCDBase *lcd = NULL);
Edit: Ok, casting explicitly works, but how do I cast for a function pointer?
Can you rebuild the library without that define? That's what I'd try first. NULL is a pretty standard macro, and should be assumed to be defined everywhere.
Right now, your problem is that C++ doesn't allow automatic casts from void * to other pointer types like C does.
From C++ Reference:
In C++, NULL expands either to 0 or 0L.
If that doesn't work, just do a global replace in the library: NULL to LIBDEFINEDNULL or something. That way you'll keep the library code intact and avoid the macro collision.
Do you have access to that libraries source? If so, I think a search and replace on their code is in order. (Replace their NULL with LIBNAME_NULL or something similar.) If that's simply not an option then I would recommend using 0 in your code instead of NULL.
I'm curious, though: What problems is that causing? They're not changing the value of null, only the default casting.
One of your comments says you've considered redefining it yourself, but you don't know what to redefine it to.
A lot of implementations will define NULL like this:
#undef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif
This is because in C, it makes sense to have it as a void pointer, because it's a pointer type that can be implicitly cast to other types.
C++ doesn't allow this (which is causing your problems), but using 0 instead of NULL works.
I think in all recent versions, GCC will actually define it to __null, which is a non-portable extension.
The most generic approach would be to wrap up the offending includes and store and restore the macros previous definition. This, however, is compiler-dependent.
This is how you could do it with VC:
#pragma push_macro("NULL")
#include <offendinglib.h>
#pragma pop_macro("NULL")
Alternatively, set the macro to what you need it to be afterwards:
#include <offendinglib.h>
#undef NULL
#define NULL 0
Yes, you do just need to cast appropriately:
Generic(std::string name, Json::Value *config, int type,
LCDBase *lcd = (LCDBase *)NULL);