Embed code through macro - c++

I try to embed a code block through the use of macro like this:
#define RUN_CODE_SNIPPET(c) do {\
c\
} while(0);
where 'c' is a code block enclosed inside '{ }'
Here is how to use it
#include <stdio.h>
#define RUN_CODE_SNIPPET(c) do {\
c\
} while(0);
int main(int argc, char *argv[]) {
RUN_CODE_SNIPPET({
//const char *message = "World";
const char message[] = {'w', 'o', 'r', 'l', 'd', '\0'};
printf("%s\r\n", message);
});
return 0;
}
You can run it here here
But I get compiler error when I use the initializer list format
test.c: In function ‘main’:
test.c:13:4: error: macro "RUN_CODE_SNIPPET" passed 6 arguments, but takes just 1
});
^
test.c:9:3: error: ‘RUN_CODE_SNIPPET’ undeclared (first use in this function)
RUN_CODE_SNIPPET({
^~~~~~~~~~~~~~~~
test.c:9:3: note: each undeclared identifier is reported only once for each
function it appears in
Seems the compiler is taking each element in the initializer list as the argument to the macro itself. The string initializer works fine.
What is wrong here?

The commas in what you pass inside the parentheses are interpreted as macro argument separators and the macro is expecting just one argument.
There are two ways around the problem:
parenthesize the commas-containing argument, i.e., pass (a,b,c) instead of a,b,c (not applicable in your case because your argument is not an expression)
use variadic macro arguments (... -> __VA_ARGS__)
In other words:
#define RUN_CODE_SNIPPET(...) do { __VA_ARGS__; }while(0)
will work (including the semicolon at the end of the macro is not advisable -- for a function-like macro, you should generally be able to do if(X) MACRO(something); else {} and the semicolon would mess that up).

Related

error: macro "assert" passed 2 arguments, but takes just 1

vector<string> foo(vector<string> s) { return s; }
assert(foo(vector<string>{"hello", "world"}) ==
vector<string>{"hello", "world"});
error: macro "assert" passed 2 arguments, but takes just 1
error: ‘assert’ was not declared in this scope
maybe define assert in gcc 11.1.0
# define assert(expr) \
(static_cast <bool> (expr) \
? void (0) \
: __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))
compiler flag is
-Wall -std=c++20
The preprocessor only has a primitive understanding of C++'s syntax, and in particular it sees any commas not enclosed in parentheses as argument separators. There are two commas in your assert call, and only one is enclosed in parentheses, so the macro thinks it's getting two arguments as follows
foo(vector<string>{"hello", "world"}) == vector<string>{"hello"
"world"});
Wrap the expression in parentheses to prevent this.
// Note: Double parens
assert((foo(vector<string>{"hello", "world"}) ==
vector<string>{"hello", "world"}));

How to pass raw string literals to [[deprecated(message)]] attribute?

I want to pass a raw string literals to [[deprecated(message)]] attribute as the message. The message is used again and again. So I want to avoid code repeat.
First, I tried to use static constexpr variable.
static constexpr auto str = R"(
Use this_func()
Description: ...
Parameter: ...
)";
[[deprecated(str)]]
void test1() {
}
I got the error "deprecated message is not a string". It seems that static constexpr variable isn't accepted by [[deprecated(message)]].
I tried to define the row string literals as preprocessor macro.
#define STR R"(
Use this_func()
Description: ...
Parameter: ...
)"
[[deprecated(STR)]]
void test2() {
}
It works as I expected as follows on clang++ 8.0.0.
prog.cc:38:5: warning: 'test2' is deprecated:
Use this_func()
Description: ...
Parameter: ...
[-Wdeprecated-declarations]
test2();
^
Demo: https://wandbox.org/permlink/gN4iOrul8Y0F76TZ
But g++ 9.2.0 outputs the compile error as follows:
prog.cc:19:13: error: unterminated raw string
19 | #define STR R"(
| ^
prog.cc:23:2: warning: missing terminating " character
23 | )"
| ^
https://wandbox.org/permlink/e62pQ2Dq9vTuG6Or
#define STR R"( \
Use this_func() \
Description: ... \
Parameter: ... \
)"
If I add backslashes on the tail of each line, no compile error occurred but output message is different from I expected as follows:
prog.cc:38:11: warning: 'void test2()' is deprecated: \\nUse this_func() \\nDescription: ... \\nParameter: ... \\n [-Wdeprecated-declarations]
I'm not sure which compiler works correctly.
Is there any way to pass the raw string literals variable/macro to [[deprecated]] attribute?
There is no such thing as a "raw string literal variable". There may be a variable which points to a string literal, but it is a variable, not the literal itself. The deprecated attribute does not take a C++ constant expression evaluating to a string. It takes a string literal: an actual token sequence.
So the most you can do is use a macro to contain your string literal. Of course, macros and raw string literals don't play nice together, since the raw string is supposed to consume the entire text. So the \ characters will act as both continuations for the macro and be part of the string.

C++ Expected string literal before args

#include <iostream>
using namespace std;
int main(int argc, char* argv[]) {
string argstr[argc];
for(int c = 1; c++; c<argc) {
argstr[c].assign(argv[c]);
}
for(int c = 1; c++; c<argc) {
__asm__(argstr[c]); //This is where the error occurs
cout << argstr[c] << endl;
}
}
If I try to compile it with MinGW, I get the following error:
Main.cpp: In function 'int main(int, char**)':
Main.cpp:15:6: error: expected string-literal before 'args'
asm(args);
I know this, that's why I assign the arguments to a vector of strings.
__asm__() is a compile-time construct. The argument must be a string literal, and not a variable.
You can't dynamically execute assembly code like this. The compiler needs to know about the assembly instructions at compile time so it can check if they are valid, but you are trying to pass them in at run time.
Edit: One workaround is to write a wrapper program in python (for example) that injects a string literal into your C++ __asm__ construct and then compiles it and executes it for you.

Why can't I use assert with std::is_same?

Can somebody explain to me why on Earth does this code snippet refuse to work?
#include <cassert>
#include <type_traits>
using namespace std;
int main()
{
assert(is_same<int, int>::value);
}
Compilation fails because, according to the compiler:
prog.cpp:7:33: error: macro "assert" passed 2 arguments, but takes just 1
assert(is_same<int, int>::value);
^
prog.cpp: In function 'int main()':
prog.cpp:7:2: error: 'assert' was not declared in this scope
assert(is_same<int, int>::value);
^
What? is_same<int, int>::value is undoubtedly one argument. Also assert is declared at this scope, and the compiler itself confirmed it in the previous error!
http://ideone.com/LcMVkn
The macro splits your parameter(s) like this:
is_same<int , int>::value
// ^^ par1 ^^// ^^ par2 ^^
As assert() is a macro definition (with one parameter), it's handled by the C-preprocessor. The preprocessor is unaware of c++ syntax like template parameters gouped in angle brackets (<>) separated with ,. So the parameter expression is split up like shown above.
You can avoid that using extra parenthesis, so the C-preprocessor will take that parameter as a whole:
assert((is_same<int, int>::value));
// ^ ^

GCC: __attribute__ ((format (printf, x, y)) does not seem to work when function is called using a variadic macro

GCC version ntoarm-gcc (GCC) 4.4.2
I've added 'printf' format attributes to all my functions that wrap printf() and co. They work perfectly fine except when calling the functions using a variadic macro.
class Log { [...]
void log_fmt(LogLevel level, const std::string& funcName, const char_t * const logFormatStr, ...) __attribute__ ((format (printf, 4, 5)));
[...] };
An incorrect direct call like
log.log_fmt(Info, "test", "wrong %u", "type");
yields warning:
format '%u' expects type 'unsigned int', but argument 5 has type 'const char*'
The same incorrect call using a macro yields no warning, however:
#define LOGI(MSG, ...) log.log_fmt(Info, __func__, (MSG), __VA_ARGS__)
LOGI("wrong %u", "type");
Can I get the warnings to show up in this case too? Have I made a mistake or is this intended behaviour?
This:
#include <iostream>
#include <cstdio>
struct log {
static void logf(std::string, std::string, const char*, ...) __attribute__((format (printf, 3, 4))) {}
};
#define L(m, ...) log::logf("no", __func__, (m), __VA_ARGS__)
int main() {
//log::logf("hi", "hi", "test %u", "hi");
L("test %u", "hi");
}
works perfectly, in the sense that it gives the correct warning, like below:
main.cpp: In function 'int main()':
main.cpp:8:61: warning: format '%u' expects argument of type 'unsigned int', but argument 4 has type 'const char*' [-Wformat=]
#define L(m, ...) log::logf("no", __func__, (m), __VA_ARGS__)
^
main.cpp:12:5: note: in expansion of macro 'L'
L("test %u", "hi");
^
At global scope:
cc1plus: warning: unrecognized command line option "-Wno-undefined-internal" [enabled by default]
So, I would guess that the problem is on the position parameters (you have put 4, 5 on your format attribute, when it seems that you should have put 3, 4)....