• #Define
    31 replies, posted
So i was going through the GWEN code,i noticed a #Define macro in the Unit test, and thought to myself, is the #Define more useful then a Templated function? Im reading up more on Define macros, but i would like to get the opinions of fellow facepunchers
[QUOTE=MickeyCantor;36145481]So i was going through the GWEN code,i noticed a #Define macro in the Unit test, and thought to myself, is the #Define more useful then a Templated function? Im reading up more on Define macros, but i would like to get the opinions of fellow facepunchers[/QUOTE] They are different. It would help if you showed us what you're talking about as my mind reading skills are not up to par.
If they are both working stuffs lets look at advantages and disadvantages. #define's will make you loose type safety and whatever you do it will replace the code where you written it. So if #defined stuff is large and used a lot, it may bloat your software. On the other hand you could use templates. You keep type safety. Easier to debug. Less error prone. And if they are small functions most probably it will going to be inlined, so there is no performance difference between them. Basically we can say #define s is not good way to do it, and I wouldn't use it. But still it may have uses since it exists. Edit: #define s are defined as evil in cpp faq :P [url]http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.5[/url]
#defines can be useful when you want quick accessors. For example, in my compiler I have this: [CODE] #define val(x) (x->Value) #define tag(x) (x->Tag) #define isatom(x) (tag(x) == Atom) #define islist(x) (tag(x) == List) #define car(x) (x->Car) #define cdr(x) (x->Cdr) #define cadr(x) (car(cdr(x))) #define cddr(x) (cdr(cdr(x))) [/CODE]
[QUOTE=Eudoxia;36146932]#defines can be useful when you want quick accessors. For example, in my compiler I have this:[/QUOTE] You're not even saving many characters on most of those.
[QUOTE=Eudoxia;36146932]#defines can be useful when you want quick accessors. For example, in my compiler I have this: [CODE] #define val(x) (x->Value) #define tag(x) (x->Tag) #define isatom(x) (tag(x) == Atom) #define islist(x) (tag(x) == List) #define car(x) (x->Car) #define cdr(x) (x->Cdr) #define cadr(x) (car(cdr(x))) #define cddr(x) (cdr(cdr(x))) [/CODE][/QUOTE] Those should be IDE macros (if even that). They just make things more complicated for anyone who isn't experienced with your code.
cddr expands to ((x->Cdr)->Cdr). I'd say that looks a little bit spaghetti. Either way, those could easily be inline functions or methods. Defines are bad.
Ok so don't use Define, got it
[QUOTE=MickeyCantor;36152920]Ok so don't use Define, got it[/QUOTE] It's not about using or not using, there's a place for it. But no, you shouldn't use define for this.
I'm a fan of 'local macros' that are restricted to one source file. They [i]can[/i] make things cleaner. In my JavaScript VM, I use these macros: [cpp] #define NEXT_UINT32() (L->INSNS[L->IP++]) #define NEXT_DOUBLE() (L->IP += 2, *(double*)&L->INSNS[L->IP - 2]) #define NEXT_STRING() (L->image->strings[NEXT_UINT32()]) #define PUSH(v) do { \ if(L->SP >= L->SMAX) { \ L->SMAX *= 2; \ if(L->STACK_CSTACK) L->STACK = memcpy(js_alloc(L->SMAX / 2 * sizeof(VAL)), L->STACK, L->SMAX / 2 * sizeof(VAL)); \ L->STACK = js_realloc(L->STACK, sizeof(VAL) * L->SMAX); \ } \ L->STACK[L->SP++] = (v); \ } while(false) #define POP() (L->STACK[--L->SP]) #define PEEK() (L->STACK[L->SP - 1]) [/cpp] [editline]2nd June 2012[/editline] It's certainly nicer to be able to write code like this, for example: [cpp] case JS_OP_PUSHNUM: { double d = NEXT_DOUBLE(); PUSH(js_value_make_double(d)); break; } [/cpp] [editline]2nd June 2012[/editline] However, try not to go crazy with macros. While sometimes useful, they can end up leaving your code an unreadable mess
[QUOTE=swift and shift;36155686]I'm a fan of 'local macros' that are restricted to one source file. They [i]can[/i] make things cleaner. In my JavaScript VM, I use these macros: [cpp] #define NEXT_UINT32() (L->INSNS[L->IP++]) #define NEXT_DOUBLE() (L->IP += 2, *(double*)&L->INSNS[L->IP - 2]) #define NEXT_STRING() (L->image->strings[NEXT_UINT32()]) #define PUSH(v) do { \ if(L->SP >= L->SMAX) { \ L->SMAX *= 2; \ if(L->STACK_CSTACK) L->STACK = memcpy(js_alloc(L->SMAX / 2 * sizeof(VAL)), L->STACK, L->SMAX / 2 * sizeof(VAL)); \ L->STACK = js_realloc(L->STACK, sizeof(VAL) * L->SMAX); \ } \ L->STACK[L->SP++] = (v); \ } while(false) #define POP() (L->STACK[--L->SP]) #define PEEK() (L->STACK[L->SP - 1]) [/cpp] [editline]2nd June 2012[/editline] It's certainly nicer to be able to write code like this, for example: [cpp] case JS_OP_PUSHNUM: { double d = NEXT_DOUBLE(); PUSH(js_value_make_double(d)); break; } [/cpp] [editline]2nd June 2012[/editline] However, try not to go crazy with macros. While sometimes useful, they can end up leaving your code an unreadable mess[/QUOTE] Could you not have the same convenience and result with inlined functions?
[QUOTE=Deco Da Man;36155861]Could you not have the same convenience and result with inlined functions?[/QUOTE] then they wouldn't be able to access local variables
[QUOTE=swift and shift;36156139]then they wouldn't be able to access local variables[/QUOTE] You pass them.
It's not the end of the world if you do use a macro here or there, even if an inline function would be 'better' in that one specific case. It's a habit to many programmers, I think, because it was the only option in C89. So while it's not ideal, it's still idiomatic in some places, and it won't automatically make your code unreadable or impossible to use, as long as you keep it under a line or two and use parens around each argument and the full expression. You should prefer static+inline functions or templates when you've got them, but I wouldn't throw a fit if I saw a macro in its place. The are occasions where the 'advantages' of one over the other are merely academic. There may also be cases where you [i]don't[/i] want type safety. Almost like compile-time duck-typing (kinda Go-esque). Not idiomatic, but I think it's OK to sometimes write non-idiomatic code if it greatly simplifies things. Like you could write: [cpp] #define dot3(a, b)\ ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z) [/cpp] and it would work with all of the following types (defined with another macro for good measure): [cpp] #define define_vec3(suffix, type)\ typedef struct vec3##suffix { type x, y, z; } vec3##suffix##_t define_vec3(i16, int16_t); define_vec3(i32, int32_t); define_vec3(u16, uint16_t); define_vec3(u32, uint32_t); define_vec3(f, float); define_vec3(d, double); [/cpp] Of course, you 'should' be using interfaces for this if you have them. They're still pretty much the only option when you want to do things that involve token concatenation or atypical metaprogramming.
So basically you should avoid them at all cost except a few edge cases. Pretty much sums up the thread.
Yeah, but I wouldn't get dogmatic about it. People should be able to read and work with any code, and shouldn't be afraid to try things that are a little different. But, you know, not be weird for the sake of being weird. Have some kind of good reason for doing things your way.
[QUOTE=ROBO_DONUT;36161202]Yeah, but I wouldn't get dogmatic about it. People should be able to read and work with any code, and shouldn't be afraid to try things that are a little different.[/QUOTE] There's nothing dogmatic about what I'm saying, if that's what you're implying. If you don't have to use define, don't use define. That makes perfect sense. EDIT: Sorry, I only noticed your edit after my final one. Seems like we're both saying the same thing.
I know what you mean, but I wanted to be clear, because newbies often take guidelines as strict rules and flip out when they encounter something that doesn't uphold their personal vision of perfect code.
[QUOTE=ROBO_DONUT;36161328]I know what you mean, but I wanted to be clear, because newbies often take guidelines as strict rules and flip out when they encounter something that doesn't uphold their personal vision of perfect code.[/QUOTE] Obviously this is very personal, but I think it's easier to teach people how to do things the preferred way and then let them figure out the edge cases by themselves. However, you should [B]always[/B] explain why. It's useless to tell someone that X makes more sense than Y and never tell him how X is better than Y. That said, if you can justify why you're doing something, that's a good step. If someone else reads your justification and thinks it makes sense, that's another good step.
[QUOTE=gparent;36157553]You pass them.[/QUOTE] not as convenient
[QUOTE=swift and shift;36163007]not as convenient[/QUOTE] Yep. That's very sad.
Why not use a macro to pass them but have the code itself in a function?
[QUOTE=Jookia;36170545]Why not use a macro to pass them but have the code itself in a function?[/QUOTE] You should reread the thread.
[QUOTE=Overv;36170767]You should reread the thread.[/QUOTE] I thought it was about using the preprocessor. I just noted a good compromise between using macros and having your code not be a mess of spaghetti.
Macros make things "somtimes" cleaner but more horrible to debug, I would rather go for inlining
[QUOTE=Zeh Matt;36181239]Macros make things "somtimes" cleaner but more horrible to debug, I would rather go for inlining[/QUOTE] if your macros are of the complexity that they need to be debugged, they really shouldn't be macros
[QUOTE=swift and shift;36191368]if your macros are of the complexity that they need to be debugged, they really shouldn't be macros[/QUOTE] Maybe you have misread my post, I don't prefer them. [url]http://msdn.microsoft.com/en-us/library/bf6bf4cf%28v=vs.80%29.aspx[/url] Read that also
I've got one question 50% related to the thread. What is better? [code] #define devmode #ifdef devmode .. print values for debugging #endif [/code] or [code] const bool devmode = true if (devmode == true) { .. print values for debugging } [/code] Is it a matter of opinion/choice of programmer? It has always bugged me as I'm not a C++ professional
[QUOTE=vombatus;36207012]I've got one question 50% related to the thread. [/QUOTE] Doing it by #ifdef way discards function when it isn't on debug mode. So could be slightly better since you will not use "if" which may increase complexity in a loop that run for million times. also there is function for it which called "TRACE" or something. even it is not implemented you can make your own. [CODE] inline void trace(...) { #ifdef DEBUG printf(...); #endif } [/CODE] So this function will be optimized in release mode to nothing and it will be like there is no function call in release mode. Also doing it in function way, you can change contents of function to output somewhere else or do any change when you need easily. Which is something you can't do with #ifdef way. Like you have to search for every #ifdef DEBUG and need to change all code one by one. But if you want to get into debug mode by regular users, you can add if(devmode) thing to your trace function. So with a parameter supplied to your application exe, people can get into debug mode and could provide you some information to help you fixing bugs. If this is the case, it will be better to use a crash reporting tool too. Which will dump the stack trace and other data to help you fix bugs. EDIT: Also there is libraries for outputting debug data to different places with different formats that you could be interested. Just search for C++ Logging library or class there will be bunch of them. I am personally using my own stuff so I can't say any of it is better than others.
[QUOTE=burak575;36208536]Doing it by #ifdef way discards function when it isn't on debug mode. So could be slightly better since you will not use "if" which may increase complexity in a loop that run for million times.[/QUOTE] Actually, having an if statement that compares two compile time constants will discard that branch as well (with corresponding optimization active), so it should not make any difference in this case.
Sorry, you need to Log In to post a reply to this thread.