How to solve Variadic Arguments issue (using C): Difference between revisions
Line 78: | Line 78: | ||
35 ! // TEST W/ ADDITIONAL variadic arguments ! | 35 ! // TEST W/ ADDITIONAL variadic arguments ! | ||
36 ! Say(0, "Error: Socket creation failed with %s\n", "just a random argument"); | 36 ! Say(0, "Error: Socket creation failed with %s\n", "just a random argument"); | ||
36 + logWithMethodName("connectAMI", 36, 0, (paramete; | 36 + logWithMethodName("connectAMI", 36, 0, (paramete; <font color="red">Note the truncated line!<font> | ||
SEVERE==========> a - CZM0277 Syntax error: possible missing ')' or ','? | SEVERE==========> a - CZM0277 Syntax error: possible missing ')' or ','? | ||
SEVERE==========> b - CZM0045 Undeclared identifier paramete. | SEVERE==========> b - CZM0045 Undeclared identifier paramete. |
Revision as of 10:59, 28 November 2019
First of all, what are Variadic Arguments (VA)? It's a way to NOT define the number of arguments a function (or method) takes. You only define the args you definitely going to be given on every call. All additional arguments are then optional, but can be used if given.
While porting C-code from Linux to AS/400 I ran into a problem. This article is going to explain the issue and the solution.
The Issue
The code used
I[1] have some code that I have been using for years in macOS and Linux projects. It's purpose is to log messages with the source's filename, line number and some custom message, depending on the severity/log level.
This is how it's used in the code:
Say(0, "Error: Socket creation failed with %s\n", "just a random argument"); // With additional arguments Say(0, "Error: Socket creation failed...\n"); // just a plain message
This is how the define adds the filename and linenumber:
#if (kDebug) #define Say(logLevel, parameter, ...) logWithMethodName(__FUNCTION__, __LINE__, logLevel, (parameter), ##__VA_ARGS__); #else #define Say(logLevel, parameter, ...) //#define KeinLoggingHeute #endif
This is the actual logging code (you can skip that, it's not relevant, except for the parameters):
void logWithMethodName(const char* methodName, int lineNumber, int logLevel, char *format, ...) { if (gLogLevel>=logLevel) { /* Variables */ char msg1[kMaxMsgLen]; char msg2[kMaxMsgLen]; char lMethodName[kMaxMethodLen]; /* Get the arguments */ va_list argp; va_start(argp, format); // format being the last argument before '...' /* Combine format and arguments! */ vsprintf(msg2, format, argp); if (strlen(methodName) > kMaxMethodLen) { memcpy(lMethodName, methodName, kMaxMethodLen-1); lMethodName[kMaxMethodLen]='\0'; } else { strcpy(lMethodName, methodName); } if (strlen(format) > kMaxFormatLen) format[kMaxFormatLen]='\0'; sprintf(msg1, "%s (%d): ", lMethodName, lineNumber); strcat(msg1, msg2); /* Output to stdout */ if (1) { printf(msg1); } /* Write to syslog */ if (0) { //logger(msg1); } va_end (argp); } return; }
What happened
Looks fine, you say? I'd agree. This code worked for me for years. Then I compiled it on our AS/400...
CRTCMOD MODULE(CTI/NTWRKNG) SRCFILE(CTI/SOURCES) SRCMBR(NETWORKING) OPTION(*LOGMSG) OUTPUT(*PRINT)
[2]
...and ran into these error messages:
35 ! // TEST W/ ADDITIONAL variadic arguments ! 36 ! Say(0, "Error: Socket creation failed with %s\n", "just a random argument"); 36 + logWithMethodName("connectAMI", 36, 0, (paramete; Note the truncated line! SEVERE==========> a - CZM0277 Syntax error: possible missing ')' or ','? SEVERE==========> b - CZM0045 Undeclared identifier paramete. 37 ! 38 ! // EMPTY variadic arguments 39 ! Say(0, "Error: Socket creation failed...\n"); 39 + logWithMethodName("connectAMI", 39, 0, (paramete; + 39 ERROR===========> a - CZM0041 The invocation of macro Say contains fewer arguments than are required by the macro definition. SEVERE==========> b - CZM0277 Syntax error: possible missing ')' or ','?
The Solution
- Links
- https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html GNU.org explaining VA
- ↑ User:Heiko
- ↑ Note the OUTPUT-Option! If not given, you will get only
Module NTWRKNG is not created because statement errors occurred.
info, and no further indication of what went wrong. WithOUTPUT(*PRINT)
given, you will receive detailed information in your print queue.