I would like to hide some complexity from some non-trivial code I'm writing. Here, I would like to hide one level of indirection from a struct pointer, to make it more readable. I'm not asking whether this is clean or a best practice or not, I know it isn't, but I also know what I like to achieve :)
So, how kosher is to have something like
#define getmark() m->o->marked
besides that fact that I would not write it in non-academic code? That would allow me to do
n->getmark()
, which is nicer (and more to the point than)
n->m->o->marked
Is the #define code correct? Will it just do a text replace here with no other strings attached?
IMHO, most C programmers would prefer a function-style macro, like:
#define getmark(m) ((m) && (m)->o ? (m)->o->marked : -1)
Quite frankly - not.
You are not making your code eaiser to read, but instead hiding the fact that there is a hidden state machine (m pointer which points to o).
You also make this hack global - which might break if someone has such variables.
Also ... the trick of adding "()" after the macro to make it look like you are calling a normal function, instead of 2 indirections... is bad. It looks for a reader like there should be a function with this name, but instead you hide a monster (poker face....).
If you need to simplify the state machine, and you know that there will be only one state - create a global static variable and create plain functions to call those objects.
It will work, but even in C it's a terrible idea. Please don't do it.
If you want to avoid the 'source bloat' of repeated indirections, use a temporary pointer.
O* myO;
myO = n->m->o;
o->marked = o->this + o->that;
A problem with your original macro is that
n->getmark() = 123;
will work while it should not.
Related
I haven't included any code because it's not important to my question, but say I have a statement like if (g_sound == 1){printf("\a");} (of course I am just using a shorter example), how could I use this code all over my program while not having so much repetitiveness? Is there some type of variable which you could link to and have the code in that variable executed? So that half my code isn't the same thing over and over again... All help is much appreciated!
UPDATE: Thank you all for your helpful comments, I figured out that using a function would be the most optimal since it is a 20 line code I need to have executed! Thanks once again!
If the statement is really that simple (or at least optimal) then use a macro:
#define THIS_IS_NOT_A_FUNCTION(X) if (x == 1){ printf ("\a");}
Then the macro is used like this:
// do some tedious task that I can't be bother typing out fully:
THIS_IS_NOT_A_FUNCTION(g_sound);
As David C. Rankin pointed out in his comment, macros are expanded to their defined value pre-compile time so don't have the overhead of calling a function. The downside is that the code can become unreadable if macros are used too liberally.
If the statement is a complex operation it may pay to write a function and call that.
I'm writing a Scheme interpreter. For each built-in type (integer, character, string, etc) I want to have the read and print functions named consistently:
READ_ERROR Scheme_read_integer(FILE *in, Value *val);
READ_ERROR Scheme_read_character(FILE *in, Value *val);
I want to ensure consistency in the naming of these functions
#define SCHEME_READ(type_) Scheme_read_##type_
#define DEF_READER(type_, in_strm_, val_) READ_ERROR SCHEME_READ(type_)(FILE *in_strm_, Value *val_)
So that now, instead of the above, in code I can write
DEF_READER(integer, in, val)
{
// Code here ...
}
DEF_READER(character, in, val)
{
// Code here ...
}
and
if (SOME_ERROR != SCHEME_READ(integer)(stdin, my_value)) do_stuff(); // etc.
Now is this considered an unidiomatic use of the preprocessor? Am I shooting myself in the foot somewhere unknowingly? Should I instead just go ahead and use the explicit names of the functions?
If not are there examples in the wild of this sort of thing done well?
I've seen this done extensively in a project, and there's a severe danger of foot-shooting going on.
The problem happens when you try to maintain the code. Even though your macro-ized function definitions are all neat and tidy, under the covers you get function names like Scheme_read_integer. Where this can become an issue is when something like Scheme_read_integer appears on a crash stack. If someone does a search of the source pack for Scheme_read_integer, they won't find it. This can cause great pain and gnashing of teeth ;)
If you're the only developer, and the code base isn't that big, and you remember using this technique years down the road and/or it's well documented, you may not have an issue. In my case it was a very large code base, poorly documented, with none of the original developers around. The result was much tooth-gnashing.
I'd go out on a limb and suggest using a C++ template, but I'm guessing that's not an option since you specifically mentioned C.
Hope this helps.
I'm usually a big fan of macros, but you should probably consider inlined wrapper functions instead. They will add negligible runtime overhead and will appear in stack backtraces, etc., when you're debugging.
I have some experience in programming in C but I would not dare to call myself proficient.
Recently, I encountered the following macro:
#define CONST(x) (x)
I find it typically used in expressions like for instance:
double x, y;
x = CONST(2.0)*y;
Completely baffled by the point of this macro, I extensively researched the advantages/disadvantages and properties of macros but still I can not figure out what the use of this particular macro would be. Am I missing something?
As presented in the question, you are right that the macro does nothing.
This looks like some artificial structure imposed by whoever wrote that code, maybe to make it abundantly clear where the constants are, and be able to search for them? I could see the advantage in having searchable constants, but this is not the best way to achieve that goal.
It's also possible that this was part of some other macro scheme that either never got implemented or was only partially removed.
Some (old) C compilers do not support the const keyword and this macro is most probably a reminiscence of a more elaborate sequence of macros that handled different compilers. Used like in x = CONST(2.0)*y; though makes no sense.
You can check this section from the Autoconf documentation for more details.
EDIT: Another purpose of this macro might be custom preprocessing (for extracting and/or replacing certain constants for example), like Qt Framework's Meta Object Compiler does.
There is absolutely no benefit of that macro and whoever wrote it must be confused. The code is completely equivalent to x = 2.0*y;.
Well this kind of macro could actually be usefull when there is a need to workaround the macro expansion.
A typical example of such need is the stringification macro. Refer to the following question for an example : C Preprocessor, Stringify the result of a macro
Now in your specific case, I don't see the benefit appart from extreme documention or code parsing purposes.
Another use could be to reserve those values as future function invocations, something like this:
/* #define CONST(x) (x) */
#define CONST(x) some_function(x)
// ...
double x, y;
x = CONST(2.0)*y; // x = some_function(2.0)*y;
Another good thing about this macro would be something like this
result=CONST(number+number)*2;
or something related to comparisons
result=CONST(number>0)*2;
If there is some problem with this macro, it is probably the name. This "CONST" thing isn't related with constants but with some other thing. It would be nice to look for the rest of the code to know why the author called it CONST.
This macro does have the effect of wrapping parenthesis around x during the macro expansion.
I'm guessing someone is trying to allow for something along the lines of
CONST(3+2)*y
which, without the parens, would become
3+2*y
but with the parens becomes
(3+2)*y
I seem to recall that we had the need for something like this in a previous development lifetime.
Is it possible to refer to a variable using multiple names in C ? I know this could be done via pointers but is it possible without using pointers. Just like we use 'typedef' for multiple naming of data type, similar for Variables
I have a constant named FILTER_PROC_LOAD_INTERNSITY, How to refer to it using simple name like 'var1'.
you may want to use macros?
#define var1 FILTER_PROC_LOAD_INTERNSITY
but the question is: why?
one "thing" one responsibility. You do not want to baffle the reader of your code. The name of the Variable seems to be wrong in the first place, if you have the need to rename the name.
Edith:
what my problem with readability is expressed in this example
char *very_ugly_variable_name;
#define beautifulVariableName very_ugly_variable_name
void unmaintainable_old_function() {
print(very_ugly_variable_name);
}
void myOtherNewFunction() {
print(beautifulVariableName);
}
you do not grok in a moment, that very_ugly_variable_name and beautifulVariableName are the exact same (in namescope and in memory).
The C language does not seem to have references (to alias your variable) but you can use a pointer to that end: yourtype* var1 = &FILTER_PROC_LOAD_INTERNSITY and then use *var1 to get the value of your constant. But this doesn't look like a good idea - symbolic names in programs are much easier to read and understand.
I'm a little bit new to C so I'm not familiar with how I would approach a solution to this issue. As you read on, you will notice its not critical that I find a solution, but it sure would be nice for this application and future reference. :)
I have a parameter int hello and I wan't to make a synonomous copy of not it.
f(int hello, structType* otherParam){
// I would like to have a synonom for (!hello)
}
My first thought was to make a local constant, but I'm not sure if there will be additional memory consumption. I'm building with GCC and I really don't know if it would recognize a constant of a parameter (before any modifications) as just a synonymous variable. I don't think so because the parameter could (even though it wont be) changed later on in that function, which would not effect the constant.
I then thought about making a local typedef, but I'm not sure exactly the syntax for doing so. I attempted the following:
typedef (!hello) hi;
However I get the following error.
D:/src-dir/file.c: In function 'f':
D:/src-dir/file.c: 00: error: expected identifier or '(' before '!' token
Any help is appreciated.
In general, in C, you want to write the code that most clearly expresses your intentions, and allow the optimiser to figure out the most efficient way to implement that.
In your example of a frequently-reused calculation, storing the result in a const-qualified variable is the most appropriate way to do this - something like the following:
void f(int hello)
{
const int non_hello = !hello;
/* code that uses non_hello frequently */
}
or more likely:
void x(structType *otherParam)
{
char * const d_name = otherParam->b->c->d->name;
/* code that uses d_name frequently */}
}
Note that such a const variable does not necessarily have to be allocated any memory (unless you take its address with & somewhere) - the optimiser might simply place it in a register (and bear in mind that even if it does get allocated memory, it will likely be stack memory).
Typedef defines an alias for a type, it's not what you want. So..
Just use !hello where you need it
Why would you need a "synonym" for a !hello ? Any programmer would instantly recognize !hello instead of looking for your clever trick for defining a "synonym".
Given:
f(int hello, structType* otherParam){
// I would like to have a synonom for (!hello)
}
The obvious, direct answer to what you have here would be:
f(int hello, structType *otherParam) {
int hi = !hello;
// ...
}
I would not expect to see any major (or probably even minor) effect on execution speed from this. Realistically, there probably isn't a lot of room for improvement in the execution speed.
There are certainly times something like this can make the code more readable. Also note, however, that when/if you modify the value of hello, the value of hi will not be modified to match (unless you add code to update it). It's rarely an issue, but something to remain aware of nonetheless.