In gcc, it appears that referencing the results of a macro expansion later inside that same expansion doesn't work. For example:
#define TESTMACRO(name) \
static int name##_func(int solNo) { \
return (solNo); \
}\
static int name##Thing = {0,##name##_func},NULL,{"", capInvSw##name}};
TESTMACRO(stuff)
This results in errors like this:
test.c:7:29: error: pasting "," and "stuff" does not give a valid preprocessing token
static int name##Thing = {0,##name##_func},NULL,{"", capInvSw##name`}};
^
test.c:9:1: note: in expansion of macro ‘TESTMACRO’
TESTMACRO(stuff)
I would expect to have a function called stuff_func created and passed into stuffThing. I believe that this works in other compilers. What is the equivalent way to do this in gcc?
You can try to run only the pre-processor on your code by passing the -E flag:
gcc -E foo.c
Which evaluates your macro to:
static int stuff_func(int solNo) { return (solNo); } static int stuffThing = {0,stuff_func},NULL,{"", capInvSwstuff`}};
That can be expanded for readability to:
static int stuff_func(int solNo) {
return (solNo);
}
static int stuffThing = {0,stuff_func},NULL,{"", capInvSwstuff`}};
And it appears that you have one extra/missing brackets } in your expanded macro.
Hope it helps.
Related
I'm trying to build a project 8051 in Keil IDE.
I have a definition to print information for purposes debug program as following:
#define LOGI(fmt, ...) printf("[I] %s:%u: "fmt, __FILE__, __LINE__, ##__VA_ARGS__)
But there are errors:
log.h(18): error C301: identifier expected
log.h(18): error C301: identifier expected
log.h(18): error C304: bad macro parameter list
Please help me fix this code, thank you.
According to the documentation, Keil C51 is based on C90. So it does not support __VA_ARGS__ that is a C99 addition.
However, you can work around this for example by this trick. Use a parenthesized argument.
#define LOGI(args) \
do { \
printf("[I] %s:%u: ", __FILE__, __LINE__); \
printf args; \
} while (0)
void f(void) {
LOGI(("address of f() = %p\n", f));
}
Another possible solution is to provide an own function with a variable number of arguments, see the example in the documentation. This is a cleaner way because you can use this function without a "hick-up" when reading the source code because of the double parentheses. But be aware that these arguments are not placed in registers, and more memory on stack and in code is used.
#include <stdio.h>
#include <stdarg.h>
void logi(const char* filename, int line, char *fmt, ...) {
va_list arg_ptr;
va_start(arg_ptr, fmt);
printf("[I] %s:%u: ", filename, line);
vprintf(fmt, arg_ptr);
va_end(arg_ptr);
}
void f(void) {
logi(__FILE__, __LINE__, "Hello %u %u", 1 , 2);
}
Note: You might want to switch to another compiler, which supports some newer standard than a 30 years old one.
I have a bunch of macros to define with same prefix and I don't want to define them one by one.
Say, I want to define like:
static constexpr str_1 = "str_1";
static constexpr str_2 = "str_2";
....
static constexpr str_100 = "str_100";
I tried:
#define DECLARE_STR(variable_prefix, val_prefix, cur, max) do { \
if ((cur) < (max)) { \
static constexpr variable_prefix##cur = val_prefix#cur; \
DECLARE_STR(variable_prefix, val_prefix, cur+1 , max) \
} while(0)
But got errors: error: expected member name or ';' after declaration specifiers
Do I have a correct way to implement this?
There are two problems with your code.
First, the do/while(0) construct is useful to ensure that macros expand to a single statement. What you want to generate are variable definitions at the global namespace, for which statements are unsuited: just remove the do/while(0). The if won't be able to do anything about declaring variables either, it can only branch at runtime on values. But in any case...
The other issue is that you're trying to call the macro recursively. The C++ preprocessor is not able to perform such recursion: a macro cannot be expanded within its own expansion. Working around that requires a lot of boilerplate to generate iteration sequences up to a limit. Fortunately(?), Boost.Preprocessor has the boilerplate already done:
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/stringize.hpp>
#define DECLARE_ONE_STR(z, n, data) \
static constexpr BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(0, data), n) = BOOST_PP_TUPLE_ELEM(1, data) BOOST_PP_STRINGIZE(n);
#define DECLARE_STR(variable_prefix, val_prefix, max) \
BOOST_PP_REPEAT(max, DECLARE_ONE_STR, (variable_prefix, val_prefix))
See it live on Coliru
In the code listed below, "LambdaTest" fails with the following error on Clang only:
shared/LambdaTest.cpp:8:31: error: variable 'array' with variably
modified type cannot be captured in a lambda expression
auto myLambdaFunction = [&array]()
^
shared/LambdaTest.cpp:7:9: note: 'array' declared here
int array[length];
The function "LambdaTest2" which passes the array as a parameter instead of capturing compiles fine on G++/Clang.
// Compiles with G++ but fails in Clang
void LambdaTest(int length)
{
int array[length];
auto myLambdaFunction = [&array]()
{
array[0] = 2;
};
myLambdaFunction();
}
// Compiles OK with G++ and Clang
void LambdaTest2(int length)
{
int array[length];
auto myLambdaFunction = [](int* myarray)
{
myarray[0] = 2;
};
myLambdaFunction(array);
}
Two questions:
What does the compiler error message "variable 'array' with variably modified type cannot be captured in a lambda expression" mean?
Why does LambdaTest fail to compile on Clang and not G++?
Thanks in advance.
COMPILER VERSIONS:
*G++ version 4.6.3
*clang version 3.5.0.210790
int array[length]; is not allowed in Standard C++. The dimension of an array must be known at compile-time.
What you are seeing is typical for non-standard features: they conflict with standard features at some point. The reason this isn't standard is because nobody has been able to make a satisfactory proposal that resolves those conflicts. Instead, each compiler has done their own thing.
You will have to either stop using the non-standard feature, or live with what a compiler happens to do with it.
VLA (Variable-length array) is not officially supported in C++.
You can instead use std::vector like so:
void LambdaTest(int length)
{
std::vector<int> array(length);
auto myLambdaFunction = [&array]()
{
array[0] = 2;
};
myLambdaFunction();
}
Thanks to both answers above for pointing out that VLAs are non-standard. Now I know what to search for.
Here are more are related links to the subject.
Why aren't variable-length arrays part of the C++ standard?
Why no VLAS in C++
I have some variables defined in makefile.init:
MY_VARIABLE = some_value
In the preprocessor settings I have this -D switch:
-DUSE_MY_VAR=\"$(MY_VARIABLE)\"
And in a source file, I have this:
static const char* my_val = USE_MY_VAR;
So this my_val will get the value set in the makefile.init file.
It compiles just fine, but the indexer complains with a warning "Bad character sequence encountered: \". Is there a way to make it understand it or maybe make it ignore this specific variable?
Ok finally found something that make both compiler and indexer happy:
my -D switch becomes (removed the escaped quotes):
-DUSE_MY_VAR=$(MY_VARIABLE)
and in the source code (thanks to Expand macro inside string literal):
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
static const char* my_val = STRINGIFY(USE_MY_VAR);
This question already has an answer here:
Using functions that return placeholder types defined in another translation unit
(1 answer)
Closed 7 years ago.
With the new return type deduction in C++14, you can write code like:
auto almostPi (void) { return 3.14159; }
and the function itself will use the return value to decide the actual return type for the function, in this case a double.
How is this done for things like a general purpose library where you don't have the source code, instead only having a header file containing something like:
auto almostPi (void);
How does the compiler in that case know to warn you if you do:
char *dodgyPointer = almostPi();
from your own code.
You can't call the function if its return type can't be deduced:
$ cat test.cpp
auto almostPi(void);
void test() {
char *dodgyPointer = almostPi();
}
$ g++ -c test.cpp --std=c++14
test.cpp: In function ‘void test()’:
test.cpp:4:24: error: use of ‘auto almostPi()’ before deduction of ‘auto’
char *dodgyPointer = almostPi();
^
The library would just have to declare the actual return type in its header.