How can I trigger existing inspections on custom functions with the same signature as the inspection ones? - clion

I've written a printf wrapper in C.
void cPrintf(const char * format, ...) {
char * newfmt = malloc(strlen(format) * 2 + 10);
va_list args;
va_start(args, format);
vsprintf(newfmt, format, args);
va_end(args);
curseDebug(newfmt);
free(newfmt);
}
It takes the same arguments as printf, can I modify the Format Specifiers inspection to apply to this function as well?
cPrintf("Pressing %d down", s->key);
// Currently Clion doesn't know that this is a format function

Related

... operator in function

Sorry for the noob question. I've been immersed in Java for the past while and the book for this course doesn't cover C++.
I have to fill in a function to add keywords (of string type) to an Item object. the prototype of the function is as follows.
void addKeywordsForItem(const Item* const item, int nKeywords, ...);
In Java ... returns the remainder of arguments as a String object and I'm guessing C++ does something similar but I don't know the name of ... so searching for it is rather difficult.
What is ... called and what does it do?
What is ... called and what does it do?
There are multiple places where ... is used in C++. The context in which you are using it, it is called variadic arguments.
The standard header cstdarg provides a type and macros to help you extract specific arguments from variadic arguments.
Example code from http://en.cppreference.com/w/cpp/utility/variadic/va_start:
#include <iostream>
#include <cstdarg>
int add_nums(int count, ...)
{
int result = 0;
va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i) {
result += va_arg(args, int);
}
va_end(args);
return result;
}
int main()
{
std::cout << add_nums(4, 25, 25, 50, 50) << '\n';
}

module_param: display value in hex instead of decimal

Is it possible to display value of module_param when read, in hex?
I have this code in my linux device driver:
module_param(num_in_hex, ulong, 0644)
$cat /sys/module/my_module/parameters/num_in_hex
1234512345
Would like to see that value in hex, instead of decimal. Or, should I use different way like debugfs for this?
There is no ready parameter type (2nd argument of module_param macro), which output its argument as hexadecimal. But it is not difficult to implement it.
Module parameters are driven by callback functions, which extract parameter's value from string and write parameter's value to string.
// Set hexadecimal parameter
int param_set_hex(const char *val, const struct kernel_param *kp)
{
return kstrtoul(val, 16, (unsigned long*)kp->arg);
}
// Read hexadecimal parameter
int param_get_hex(char *buffer, const struct kernel_param *kp)
{
return scnprintf(buffer, PAGE_SIZE, "%lx", *((unsigned long*)kp->arg));
}
// Combine operations together
const struct kernel_param_ops param_ops_hex = {
.set = param_set_hex,
.get = param_get_hex
};
/*
* Macro for check type of variable, passed to `module_param`.
* Just reuse already existed macro for `ulong` type.
*/
#define param_check_hex(name, p) param_check_ulong(name, p)
// Everything is ready for use `module_param` with new type.
module_param(num_in_hex, hex, 0644);
Check include/linux/moduleparam.h for implementation module_param macro and kernel/params.c for implementation of operations for ready-made types (macro STANDARD_PARAM_DEF).

Variadic templates vs vsnprintf

While attempting to upgrade the following function to C++11
int inline formatText(const char* const fmt, ...)
{
va_list args;
va_start(args, fmt);
int len = std::min(vsnprintf(m_text, m_textSize, fmt, args), m_textSize);
va_end(args);
m_text[len] = '\0'; // assume m_textSize is storage size - sizeof('\0')
return len;
}
Obviously since printf deals with PODs, it's not really a problem for this function to accept its arguments by value.
But I realized I wasn't clear on how to achieve macro-like exact forwarding of the arguments, I realize that by inlining a simple version of this the compiler can eliminate pass-by-value, but I'm not exactly sure which of the three following approaches is technically best:
template<typename... Args>
#if defined(APPROACH_1)
int formatText(const char* const fmt, Args...)
#elif defined(APPROACH_2)
int formatText(const char* const fmt, const Args&...)
#else
int formatText(const char* const fmt, Args&&...)
#endif
{
int len = std::min(snprintf(m_text, m_textSize, fmt, std::forward<Args>(args)...);
m_text[len] = '\0';
return len;
}
Since we're talking printf here, copy-by-value isn't terrible, because I shouldn't be passing it non-pod objects; specifying const ref would certainly help complex objects that I don't want copying but clearly is counter-productive for the normal use cases of printf. I'm plain not sure what the side-effects of approach 3 are.
Everything I've read so far has left me with the impression that 'Args&&...' is likely to be the normal case for variadic templates, but in this case my gut tells me to go for approach #1.

fprintf doesn't print const char * to file

I have a simple log function that needs to print the current date and time. I'm doing it inside a function that returns a char *. When I try to set this char * into fprintf(), it doesn't print me the string into the file: why?
Here is the function that constructs the date-time:
char * UT::CurrentDateTime()
{
char buffer [50];
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
int n=sprintf(buffer, "%d:%d:%d %d:%d:%d:", (now->tm_year + 1900),
(now->tm_mon + 1), now->tm_mday, now->tm_hour, now->tm_min,
now->tm_sec);
return buffer;
}
Here is the log:
const char *time =__TIME__; // compilation time
char *currentTime = UT::CurrentDateTime(); // it's a static method; also tried to set it to const
fprintf(fp, "%s %s %s %s %s %d %s\n", __TIME__, pType, __DATE__,
currentTime, pFileName, lineNo, pMsg.c_str());
fflush(fp);
Every thing is printed except the date/time char *.
Why?
char * UT::CurrentDateTime()
{
char buffer [50];
/* ... */
return buffer;
}
You've returned a pointer to a memory buffer that dies immediately. Any function that uses the pointer returned from CurrentDateTime() is relying upon garbage.
Your compiler should have warned you about this. Disregard your compiler warnings at your own peril.
Instead, either allocate this via char *buffer = malloc(50 * sizeof char); or use C++'s memory allocation mechanisms to allocate memory that can live longer than the time the function is 'live' and running.

Is there a format specifier that always means char string with _tprintf?

When you build an app on Windows using TCHAR support, %s in _tprintf() means char * string for Ansi builds and wchar_t * for Unicode builds while %S means the reverse.
But are there any format specifiers that always mean char * string no matter if it's an Ansi or Unicode build? Since even on Windows UTF-16 is not really used for files or networking it turns out to still be fairly often that you'll want to deal with byte-based strings regardless of the native character type you compile your app as.
The h modifier forces both %s and %S to char*, and the l modifier forces both to wchar_t*, ie: %hs, %hS, %ls, and %lS.
This might also solve your problem:
_TCHAR *message;
_tprintf(_T("\n>>>>>> %d") TEXT(" message is:%s\n"),4,message);
You can easily write something like this:
#ifdef _UNICODE
#define PF_ASCIISTR "%S"L
#define PF_UNICODESTR "%s"L
#else
#define PF_ASCIISTR "%s"
#define PF_UNICODESTR "%S"
#endif
and then you use the PF_ASCIISTR or the PF_UNICODESTR macros in your format string, exploiting the C automatic string literals concatenation:
_tprintf(_T("There are %d ") PF_ASCIISTR _T(" over the table"), 10, "pens");
I found, that '_vsntprintf_s' uses '%s' for type TCHAR and works for both, GCC and MSVC.
So you could wrap it like:
int myprintf(const TCHAR* lpszFormat, va_list argptr) {
int len = _vsctprintf(lpszFormat, argptr); // -1:err
if (len<=0) {return len;}
auto* pT = new TCHAR[2 + size_t(len)];
_vsntprintf_s(pT, (2+len)*sizeof(TCHAR), 1+len, lpszFormat, argptr);
int rv = printf("%ls", pT);
delete[] pT;
return rv;
}
int myprintf(const TCHAR* lpszFormat, ...) {
va_list argptr;
va_start(argptr, lpszFormat);
int rv = myprintf(lpszFormat, argptr);
va_end(argptr);
return rv;
}
int main(int, char**) { return myprintf(_T("%s"), _T("Test")); }

Resources