Invalid arguments error when passing macros in c++ - c++

There is a function like:
int kvm_vcpu_ioctl(int vcpu_fd,int type, ...)
{
int ret;
void *arg;
va_list ap;
va_start(ap, type);
arg = va_arg(ap, void *);
va_end(ap);
ret = ioctl(vcpu_fd, type, arg);
if (ret == -1)
ret = -errno;
return ret;
}
and when I want to call it but pass a macro as the argument like:
kvm_vcpu_ioctl(vcpus.fds[vcpu_id],KVM_NITRO_GET_SREGS,sregs);
in which defined macro is:
#define KVM_NITRO_GET_SREGS _IOR(KVMIO, 0xE9, struct kvm_sregs)
I get this error:
Invalid arguments '
Candidates are:
int kvm_vcpu_ioctl(int, int, ...)
I do not why?
_IOR is :
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
and _IOC is:
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))

Your definition of KVM_NITRO_GET_SREGS "calls" _IOR with a third argument of struct kvm_sregs. From the definition of _IOR, it would appear that perhaps a sizeof(struct kvm_sregs) might be more appropriate. Or perhaps you have arguments out of order, since it appears the first argument to _IOR should possibly be a type, but I'm not sure what KVMIO expands to...
Look for other locations where _IOR is used in other drivers, and mimic those.

Related

Variadic template with printf argument checking

I have a printf-style function that takes a variable number of arguments. Here is my starting point:
#include <stdio.h>
#include <stdarg.h>
void MyPrint (const char* fmt,...)
{
va_list arglist ;
va_start (arglist, fmt) ;
vprintf (fmt, arglist) ;
va_end (arglist) ;
}
int main()
{
MyPrint ("Hello, %s\n", "world") ;
}
This prints Hello, world as expected.
Now I want to make two changes. First, I want to check the format string using the format attribute of g++. So I declare the MyPrint function first (I have to declare it first, because for some reason g++ doesn't let you assign attributes to a function definition):
void MyPrint (const char* fmt,...) __attribute__ ((format (printf, 1, 2))) ;
Now if I try e.g. MyPrint ("Hello, %d\n", "world") ; I get a nice error message.
The second change I want to make is to use a variadic template parameter. Like this:
#include <utility> // for std::forward
template<typename...Params>
void MyPrint (Params&&... fmt)
{
printf (std::forward<Params> (fmt)...) ;
}
This works too. So I combine the two, by adding the format-checking attribute to the variadic function template with this forward declaration:
template<typename...Params>
void MyPrint (Params&&... fmt) __attribute__ ((format (printf, 1, 2))) ;
But now I get this error message (gcc 10.2):
<source>: In substitution of 'template<class ... Params> void MyPrint(Params&& ...) [with Params = {const char (&)[11], const char (&)[6]}]':
<source>:15:38: required from here
<source>:8:6: error:
'format' attribute argument 2 value '1' refers to parameter type
'const char (&)[11]'
This has got me completely baffled. Can anybody tell me what I'm doing wrong?
Here is the complete program:
#include <stdio.h>
#include <utility> // for std::forward
template<typename...Params>
void MyPrint (Params&&... fmt) __attribute__ ((format (printf, 1, 2))) ;
template<typename...Params>
void MyPrint (Params&&... fmt) // <-- Line 8
{
printf (std::forward<Params> (fmt)...) ;
}
int main()
{
MyPrint ("Hello, %s\n", "world") ; // <-- Line 15
}
You can make the first error go away by adding a fixed const char * argument as the format string and pointing the attribute to that.
template<typename...Params>
void MyPrint (const char * format, Params&&... fmt) __attribute__ ((format (printf, 1, 2))) ;
template<typename...Params>
void MyPrint (const char * format, Params&&... fmt) // <-- Line 9
{
printf (format, std::forward<Params> (fmt)...) ;
}
Which reveals another error:
test.cc:8:6: error: ‘format’ attribute argument 3 value ‘2’ does not refer to a variable argument list
8 | void MyPrint (const char * format, Params&&... fmt) // <-- Line 9
| ^~~~~~~
It seems that the attribute for checking the printf archetype relies on one const char * argument and a variable argument list and is not willing to work without them. So you have to give up either the C++ template magic or the compile-time format string checking.

how to use variadic functions with functions as arguments and pass them to pointers

I am passing functions to function pointers
void tact::setFunctions(void short_press_function(void), void release_press_function(void), void long_press_function(void))
{
short_ptr = short_press_function;
release_ptr = release_press_function;
long_ptr = long_press_function;
}
But these 3 pointers will not always be used in my programs. I want to use a variadic function to pass a variable number of functions depending on which functionalities I turned ON.
void tact::setFunctions(void args(), ...)
{
va_list ap;
va_start(ap, args);
#if SHORT_BUTTON_PRESS_CONFIG
short_ptr = va_arg(ap, void (*)());
#endif
#if BUTTON_RELEASE_CONFIG
release_ptr = va_arg(ap, void (*)());
#endif
#if LONG_BUTTON_PRESS_CONFIG
long_ptr = va_arg(ap, void (*)());
#endif
va_end(ap);
}
In this new function, I thing I did not understand correctly how to use va_arg(). I basically just want to pass the address of my arguments to my pointers. How?
Thanks!

Detect this variable availability

I am currently adapting a Windows C++ project to make it work on Linux.
I defined several macros to print formatted lines to a log file.
They are printf-like so I can write this:
WARN("%d::%s<", 42, "baz");
It's pretty easy to print something like:
[thread_id][WARN][/path/to/main.cpp:15][Fri 03/01/2019
10:38:54.408][this_value] 42::baz<
this_value is value of this or NULL if this is not defined (static function, extern "C" function).
My current code is:
#if defined(_WIN32) && !defined(__INTELLISENSE__)
#define SET_ZIS __if_exists (this) { zis = this; }
#else
#define SET_ZIS
#endif
#define _LOG(...) \
do \
{ \
void *zis = NULL; \
SET_ZIS \
GetLoggerInstance()->logMessage(__VA_ARGS__); \
} while(0)
#define LOG(...) _LOG(level, __FILE__, __LINE__, __func__, zis, __VA_ARGS__)
#define WARN(...) LOG(ILogger_level::LEVEL_WARN, __VA_ARGS__)
Is there a standard way to detect if this exists?
Maybe using std::is_* or a SFINAE trick ?
I use extern-ed "C" functions to construct objects ("this" is meaningless) and call members on instanciated objects ("this" is meaningful). "Constructors" are exported in a shared object and dynamically consumed by a C++ project. Doing it that way, I don't have to manage mangled names.
extern "C" int CreateMyClass(std::shared_ptr<MyClass> *newClass);
int CreateMyClass(std::shared_ptr<MyClass> *newClass)
{
RELAY("(%p)", newClass);
*newClass = std::make_shared<MyClass>(42, "baz");
return 0;
}
MyClass::MyClass(int a, char *b)
{
RELAY("(%d,%s)", a, b);
}
EDIT: Here's a simple test case:
#include <memory> /* For std::shared_ptr */
#define RELAY(...) printf("[%p][%s]\n", this, __func__)
class MyClass
{
public:
MyClass(int a, const char *b);
static void test();
};
extern "C" int CreateMyClass(std::shared_ptr<MyClass> *newClass);
int CreateMyClass(std::shared_ptr<MyClass> *newClass)
{
RELAY("(%p)", newClass);
*newClass = std::make_shared<MyClass>(42, "baz");
return 0;
}
MyClass::MyClass(int a, const char *b)
{
RELAY("(%d,%s)", a, b);
}
void MyClass::test()
{
RELAY("()");
printf("some work");
}
int main(int argc, char **argv)
{
std::shared_ptr<MyClass> newClass;
int ret = CreateMyClass(&newClass);
MyClass::test();
return ret;
}
g++ gives the following errors:
test.c: In function ‘int CreateMyClass(std::shared_ptr<MyClass>*)’:
test.c:2:41: error: invalid use of ‘this’ in non-member function
#define RELAY(...) printf("[%p][%s]\n", this, __func__)
^
test.c:14:3: note: in expansion of macro ‘RELAY’
RELAY("(%p)", newClass);
^~~~~
test.c: In static member function ‘static void MyClass::test()’:
test.c:2:41: error: ‘this’ is unavailable for static member functions
#define RELAY(...) printf("[%p][%s]\n", this, __func__)
^
test.c:26:3: note: in expansion of macro ‘RELAY’
RELAY("()");
^~~~~
CreateMyClass is not static ("non-member function"), so this is unavailable. Same thing for the static function.
The this reference only exists and always exists inside the non-static member functions of a c++ class/struct. It's a pointer to the memory address of the instance of the class a function is operating on. As far as logging is concerned, I'm not sure how you'd use that aside from digging through a memory dump, and I'm not 100% sure that the instance address would even be useful for that.

How to use variadic macros?

I am trying to use variadic macros. I want PRINTF macro to be called from MY_TOP_PRINTF macro.
1.Either I am getting compilation error.
2.If I remove compilation error, it is only printing 1st argument.
My expected result is Inside TOP_PRINT dog here 4
#include <iostream>
#include <cstdio>
using namespace std;
#define PRINTF(str, ...) { \
fprintf(stderr, (str), ##__VA_ARGS__); \
}
#define MY_TOP_PRINTF(EXPRESSION, ...) { \
PRINTF("Inside TOP_PRINT ", EXPRESSION, __VA_ARGS__);\
}
int main()
{
int x = 4;
char str[255] = "dog here";
MY_TOP_PRINTF(str,x);
return 0;
}
Error:
hello_temp.cpp: In function ‘int main()’:
hello_temp.cpp:8:41: warning: too many arguments for format [-Wformat-extra-args]
fprintf(stderr, (str), ##__VA_ARGS__); \
^
hello_temp.cpp:13:5: note: in expansion of macro ‘PRINTF’
PRINTF("Inside TOP_PRINT", EXPRESSION, __VA_ARGS__);\
^
hello_temp.cpp:23:2: note: in expansion of macro ‘MY_TOP_PRINTF’
MY_TOP_PRINTF(str,x);

Log(PCTSTR format,...) and Log(PCTSTR text): error C2668 ambiguous call to overloaded function

I have the following defined:
void LogMessage(PCTSTR text);
void LogMessage(PCTSTR format, ...);
If I just want to call the function with one parameter, I get the following error message:
Source.cpp(10): error C2668: 'Log' : ambiguous call to overloaded function
could be 'void Log(PCTSTR,...)' or 'void Log(PCTSTR)'
while trying to match the argument list '(const wchar_t [42])'
Is it possible to do a static_cast to explizite use the first version? Or haw can this be solved, except by renaming the first or second function?
How about the following? I haven't tested on VC++ (which seems to be your platform of choice) but hopefully the version you are using implements enough C++11 for this to work.
#include <iostream>
#include <cstdio>
#include <cstdarg>
void LogMessageWorker(char const* format, ...)
{
// 1k should be enough for anyone... ;)
char buf[1024] = { 0 };
// The version of vsnprint called should always null terminate correctly and doesn't
// strictly need the -1 but I believe that the implementation that is included with
// VC++ leaves a lot to be desired so you may need to slightly tweak this.
va_list args;
va_start (args, format);
vsnprintf (buf, sizeof (buf) - 1, format, args);
va_end (args);
std::cout << "LogMessage: " << buf << std::endl;
}
template <class... Arguments>
void LogMessage(char const* format, Arguments... arguments)
{
LogMessageWorker (format, std::forward<Arguments>(arguments)...);
}
void LogMessage(char const* text)
{
LogMessageWorker ("%s", text);
}
int main(int argc, char **argv)
{
LogMessage ("The test is starting...");
for (int i = 0; i < 3; i++)
LogMessage ("This is test #%d", i);
LogMessage ("This contains the % character and still it works (%d-%d-%d-%d)");
return 0;
}