So I have some code that is throwing me an error and I am not sure why. I am using a macro to generate myself a string array and an enum that I can use to access the string array in a intuitive way. My compiler is complaining about my macro but the rest of my code seems to work as if the macro successfully created the enum which has me quite confused.
The macro is as follow
#define FOR_EACH_PHASE(PHASE) \
PHASE(init) \
PHASE(framerate) \
PHASE(priority) \
PHASE(time) \
PHASE(powersave) \
PHASE(performance) \
PHASE(response)
#define GENERATE_ENUM(ENUM) AI_phase_##ENUM,
#define GENERATE_STRING(STRING) "AI_phase_"#STRING,
typedef enum PHASE_ENUM PHASE_ENUM_t;
enum PHASE_ENUM {
FOR_EACH_PHASE(GENERATE_ENUM)
END
};
static const char* PHASE_STRINGS[] = {
FOR_EACH_PHASE(GENERATE_STRING)
};
Lines such as these seems to compile without error
struct phase_profile* set_defaults;
set_defaults = AI_phases_get_name(PHASE_STRINGS[AI_phase_framerate]);
But the compiler is giving me the following error for each line of my FOR_EACH_PHASE macro
error: 'performance' undeclared (first use in this function)
Any ideas from anyone that knows more about this than me?
Cheers
I don't have the required reputation to comment so I am posting this as an answer.
I believe you need this:
https://www.codeproject.com/Articles/32000/Improving-C-Enums-Adding-Serialization-Inheritance
I use it for some years now and it is fine!
Related
Problem
Using GObject and C, I am trying to create a subclass of the class GObject named "Bar" in module "Foo". However, the macro "G_DECLARE_FINAL_TYPE" (defined in gobject/gtype.h) expands incorrectly. Instead of expanding into FOO_BAR, it expands into nothing. So instead of expanding into:
... FooBar * FOO_BAR (gpointer ptr) { ...
It instead expands into:
... FooBar * (gpointer ptr) { ...
Error Message
I expect it to compile but instead gcc gives a syntax error:
In file included from /usr/include/glib-2.0/gobject/gobject.h:24,
from /usr/include/glib-2.0/gobject/gbinding.h:29,
from /usr/include/glib-2.0/glib-object.h:22,
from foo-bar.h:4,
from foo-bar.c:1:
/usr/include/glib-2.0/gobject/gtype.h:1407:77: error: expected ‘)’ before ‘ptr’
1407 | USED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
| ^~~
foo-bar.h:10:1: note: in expansion of macro ‘G_DECLARE_FINAL_TYPE’
10 | G_DECLARE_FINAL_TYPE (FooBar, foo_bar, FOO, BAR, GObject)
| ^~~~~~~~~~~~~~~~~~~~
Definition of Macro
This definition comes from the glib 2.66.7 library. I did not define it myself. I include it for the sake of completeness.
#define G_DECLARE_FINAL_TYPE(ModuleObjName, module_obj_name, MODULE, OBJ_NAME, ParentName) \
GType module_obj_name##_get_type (void); \
G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
typedef struct _##ModuleObjName ModuleObjName; \
typedef struct { ParentName##Class parent_class; } ModuleObjName##Class; \
\
_GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, ParentName) \
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ModuleObjName##Class, g_type_class_unref) \
\
G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); }\
G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \
G_GNUC_END_IGNORE_DEPRECATIONS
Partial Pre-Processor Output
I included the definition that contains the syntax error and formatted it for readability:
__attribute__((__unused__)) static inline FooBar * (gpointer ptr) {
return (((FooBar*) g_type_check_instance_cast ((GTypeInstance*) (ptr), (foo_bar_get_type ()))));
}
What's odd is that the definition following does get pre-processed correctly:
__attribute__((__unused__)) static inline gboolean FOO_IS_BAR (gpointer ptr) {
return ((__extension__ ({
GTypeInstance *__inst = (GTypeInstance*) (ptr);
GType __t = (foo_bar_get_type ());
gboolean __r;
if (!__inst) __r = (0);
else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0));
else __r = g_type_check_instance_is_a (__inst, __t); __r; })));
}
Full Minimal Example
I have included a minimal example that causes my error below.
foo-bar.h
#ifndef FOO_BAR
#define FOO_BAR
#include <glib-object.h>
G_BEGIN_DECLS
#define FOO_TYPE_BAR (foo_bar_get_type ())
G_DECLARE_FINAL_TYPE (FooBar, foo_bar, FOO, BAR, GObject)
G_END_DECLS
#endif /* FOO_BAR */
foo-bar.c
#include "foo-bar.h"
struct _FooBar
{
GObject parent_instance;
};
G_DEFINE_TYPE (FooBar, foo_bar, G_TYPE_OBJECT);
static void foo_bar_class_init (FooBarClass *klass)
{
}
static void foo_bar_init (FooBar *app)
{
}
makefile
foo-bar.o: foo-bar.c
gcc -c foo-bar.c $(shell pkg-config --cflags gobject-2.0) -o foo-bar.o
# included to debug the macro
foo-bar.pp: foo-bar.c
gcc -E foo-bar.c $(shell pkg-config --cflags gobject-2.0) -o foo-bar.pp
Versions
glib 2.66.7
gcc 10.2.1
Linux (Fedora 33)
What I have tried
I have studied glib's documentation on how to create a new class and as far as I can tell I am doing it correctly. I have also looked up how token pasting and macro expansion work, and also tried googling my error. It must be something obvious, but I cannot figure out what. I also tried declaring a derivable class with private data, but while finding a minimal example I changed it to a final class without private data and still have the same error. I read about the ## operator here and still cannot tell what is going wrong.
Related Stack Overflow Questions
Finally, I have looked at the following related stackoverflow posts:
My error is that concatenated tokens are not being emitted by the pre-processor. In this post the user defines their own macro and asks why one invocation works and the other doesn't. I am using a library and not my own macro.
This question is asking about why a macro expands differently in unicode mode versus ascii mode. I am not dealing with unicode so it is not relevant.
I am not using C++, only C which does not have syntax for generics, so this question does not apply to me.
Since I am not using XCode this question does not solve my problem.
I understand how macro expansion is supposed to work, so this question does tell me anything I don't already know.
I am not defining any new macros and do not have and problems with namespace collision, unlike this question.
In this and this question the user is not aware of the concatenation operator in macros. I am, and my problem is that it does not work the way I expect it too. So saying the operator exists does not help me.
This question is close to my problem, but it is occuring because an argument to a macro was not provided. I am providing all arguments so it does not help me.
This question the user is using the pasting operator when they don't need to.. In my case the pasting operator is necessary.
Well, it was something dumb. Posting this in case anyone runs across this answer.
The problem is my include guard. It should be FOO_BAR_H since the name of the file is foo-bar.h. However, it is defined as FOO_BAR. When gobject generates the token "FOO_BAR" the pre-processor realizes that it is a macro that has already been defined, but in this case the definition is empty. Nevertheless, it replaces the macro with its definition.
The solution is just replacing "FOO_BAR" with "FOO_BAR_H" in the include guard.
I'm trying to move every declaration of the following macro into another memory segment. It works fine without the section attribute. Any ideas on why I can't use it here, and how I could make it work?
#define RINGBUFFER_DECLARE_MEMB(var, sz) \
uint8_t var ## __buf[sz] __attribute__((section(".rambss"))); \
struct ring_buffer var __attribute__((section(".rambss")))
device.h:91:29: error: section attribute not allowed for
'__iso_buf__buf'
RINGBUFFER_DECLARE_MEMB(__iso_buf, BUF_SIZE_ISOLATED);
Stupid me, the problem was that the macro was used in a structure defenition:
struct a {
RINGBUFFER_DECLARE_MEMB(umama, 3);
};
Which is ofcourse not allowed
I was working with an embedded kernel source when I saw something like this:
#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, clksrc_nr, clksrc_src) \
static void __init omap##name##_timer_init(void) \
{ \
omap2_gp_clockevent_init((clkev_nr), clkev_src); \
omap2_gp_clocksource_init((clksrc_nr), clksrc_src); \
}
and when I tryed to make a program that used this ## thing (that I don't know the name) to see what it could really do I didn't got it to work. Below is what I did to test it's function. I just want to see if the argument inside the ## is literal or not, but something is clearly missing in my code for it to compile...
#include <stdio.h>
#include <stdlib.h>
#define DEFINE_1 2
#define DEFINE_2 4
#define DEFINE_3 6
#define DEFINE_i 9
int main(void)
{
int i;
for(i=1;i<4;i++) {
printf("numero %d = %d\n",i,DEFINE_##i##);
}
return EXIT_SUCCESS;
}
The output of gcc is:
test.c: In function ‘main’:
test.c:14:5: error: stray ‘##’ in program
test.c:14:33: error: ‘DEFINE_’ undeclared (first use in this function)
test.c:14:33: note: each undeclared identifier is reported only once for each function it appears in
test.c:14:42: error: expected ‘)’ before ‘i’
test.c:14:42: error: stray ‘##’ in program
Anyone knows what is wrong? Thanks
It's the token concatenation operator for the C preprocessor. The reason your example doesn't compile is because you're not using the ## operator within a macro (i.e. #define statement).
Here's another post with some more information.
## means concatenation at time of preprocessing.
http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html
You can use ## in the preprocessor directives only.
## is used for concatenation in C preprocessor macros.
In your example, the idea is to concatenate omap with the function name. For example
OMAP_SYS_TIMER_INIT(foo, ...)
will create a function named omapfoo.
## is token pasting operator and you can only use it in a macro definition. You cannot use it outside a macro definition.
Maybe what you are trying to do is, DEFINE_ and (i=1) will concatenate using ## to form "DEFINE_1" and that will be your macro with value 2. Right? If that's the case, the problem is that, macro is preprocessor and value will be get in lined before execution. So it looks for DEFINE_i and there is no such macro. Keep it in mind i=1,2,3.. and so on during runtime.
I declare macros which would make it easy to replicate the logic of writing to a file Log
I end up getting the error C2065: 'flog' : undeclared identifier.
But I don't get this error for log_buffer.
I am using Visual Studios 2008 IDE.
What am i doing wrong?
#ifndef ERROR_LOG_MACRO
#define ERROR_LOG_MACRO 1
#define SETERRORPARAMS char log_buffer[MAX_PATH]; \
char flog[MAX_PATH]; \
FILE *err_log_fp;
/*
Arguments: x (Name of the File)
y (File Path without the Filename)
z (Mode)
*/
#define OPENFILE(x,y,z) strcpy(flog,y); \
strcat(flog,"\\"); \
strcat(flog,x); \
err_log_fp = fopen(flog, z);
#define WRITELOG(x) if(err_log_fp) \
fwrite(log_buffer, sizeof(char), strlen(log_buffer), err_log_fp);
#define CLOSEFILE if(err_log_fp) \
fclose(err_log_fp);
#endif
I even tried to do
#define OPENFILE(x,y,z) SETERRORPARAMS \
... \
But even this did not work.
You probably have trailing whitespaces after the first line of your macro:
#define SETERRORPARAMS char log_buffer[MAX_PATH]; \______ <-- make sure you have no whitespaces
char flog[MAX_PATH]; \
FILE *err_log_fp;
Either that, or you're not using the macro and log_buffer is declared elsewhere.
Have you actually checked that flog is in scope wherever you're using the OPENFILE macro?
Such as with the code segment:
SETERRORPARAMS
OPENFILE (fileStr, pathStr, modeStr)
Worst case, you'll have to examine the code after the preprocessor has done its work. Most compilers will let you examine the output produced by that preprocessor stage. GCC would use gcc -E but I'm not sure what the equivalent is to MSVC.
This link seems to indicate you can enter /P into the project settings to get the preprocoessed files written to *.i files.
But, I've got to say this, using macros for this is not really a good idea. In the old days, it used to be good for speed purposes but it's not really necessary in these days of inline functions and very good code optimisers.
I have a bunch of generated functions from a supplier's tool are required to be defined by me.
Since the inner functionality of each and every one of these functions are exactly the same, I figured I could use a macro to make my life easier.
Here is the offending warning:
pasting "<function_name>" and "(" does not give a valid preprocessing token
Now, I define my macro as follows:
#define HANDLE_FUNCTION(x) \
void <function_prefix>_ ## x ## (void) \
{ \
x ## _Flag = TRUE; \
}
In my code I then write:
HANDLE_FUNCTION(fn1)
HANDLE_FUNCTION(fn2)
...and so on
Any thoughts on why this occurs?
Remove the second ##, it has no use (you don't want to make one symbol of function_name().