In C can you pass a macro with multiple values to a function - macros

I have a messaging function that takes a variable amount of arguments because it supports string formatting in the same way printf does. My plan was to then define message code and messages with a single #define and be able to call this function by passing it a single argument for something that is tightly related.
Here is the message macro:
#define MSG(a, b, ...) message(__FILE__, __LINE__, a, b, __VA_ARGS__);
And here is an example of the message code and string define:
#define MSG_INIT 0000,"%s INITIALIZED SUCCESSFULLY"
The issue is occurring when I try to make a call in the form of:
MSG(MSG_INIT);
My IDE is giving me an error along the lines of:
'Expands to message("file.c", 1, 0000, "INITIALIZED SUCCESSFULLY",);
where the last ',' is causing the issue.
I was expecting to see:
'Expands to message("file.c", 1, 0000, "INITIALIZED SUCCESSFULLY");
If I change the call to:
MSG(MSG_INIT,NULL);
All is good but I'd rather not pass the NULL because the point of the MSG_INIT define in the first place was to pass less parameters. There are messages that make use of the __VA_ARGS__ (Example: #define MSG_CONNECT 0001,"CONNECTION TO [%s] ESTABLISHED" with matching call MSG(MSG_CONEST, server_ip);) so getting rid of that is not an option. I am just looking for the best way to fix this problem and I'm aware a lot of people suggest staying away from the preprocessor but this was the best solution I thought of.

I'm aware a lot of people suggest staying away from the preprocessor ...
I wonder why that is. Could it possibly be for the same reason you had to ask this question? :-)
Honestly, the pre-processor should be limited pretty much to including header files and doing conditional compilation. Anything else that it used to be used for, such as:
#define RC_OK 0
#define RC_NOMEM 1
#define HALF_OF(x) x / 2
is far better done with enumerations or functions.
The days of function-like macros should be put behind us, especially since modern compilers can quite easily out-optimise most hand-crafted code, and without subtle errors creeping in such as with that HALF_OF macro above (do not use it, I specifically made it buggy to illustrate a point).
It's really just a text substitution thing, one which understands the lexical elements, but not the full grammar of C. The fact that you have to perform what I call "macro gymnastics" to get it to do anything other than simple stuff is reason enough to steer clear. Use functions for this, it'll make your life a lot easier.
And apologies for not solving your specific issue, I just think any solution using the pre-processor is going to be half-baked at best. But there's plenty of precedent on SO for answering the question "How do I X?" with "Don't X, it's better to Y." Think of writing an accounting package in assembler, an operating system in object-oriented COBOL, or anything in Pascal :-)
But, if you really wanted to stick to macros against my advice, you could try starting with something like:
#include <stdio.h>
#define MSG(fmtStr, ...) printf("%s:%d> " fmtStr, __FILE__, __LINE__, __VA_ARGS__)
#define MSG_INIT "Initialised %s\n"
#define MSG_TERM "Terminated %s with values %d and %d\n"
int main(void) {
MSG("%f\n", 42.3);
MSG(MSG_INIT, "something");
MSG(MSG_TERM, "something else", 7, 42);
}
I think that's portable, and it allow you to put the heavy lifting into MSG and using a separate format string and parameters for the rest of the stuff:
testprog.c:8> 42.300000
testprog.c:9> Initialised something
testprog.c:10> Terminated something else with values 7 and 42

Related

Macros do not allow definition of lexical variables

This code that uses (experimental) macros:
use experimental :macros;
macro new-var() {
quasi {
my $a = 42
}
};
new-var;
say $a
Fails with Variable '$a' is not declared, although the macro passes through without an error. If that's a correct macro declaration, what does it do? If it's not, is there a way to define new variables from within a macro?
The answer from moritz is correct about the state of macros, though from what I know of the work being done in 007, I don't think the program as written would be correct even with a working implementation of Perl 6 macros.
Perl 6 macros will not be textual in nature (C macros are an example of textual ones). A quasi is a quote construct, much like we have quotes for strings and regexes, except that it quotes Perl 6 code, representing it as something AST-ish. (I once would have said that it produces AST, but it's been realized that if an infix were to be interpolated inside of a quasi, then it comes with a precedence and associativity, and we we can't actually form the correct tree for the expression until after interpolation.)
There's a macro concept of "hygiene", whereby symbols declared in the macro body should not, by default, leak out to the place that the macro is applied, since they may well just be implementation details. One would have to explicitly ask to put a symbol into the compiling context where the macro is applied. So I expect the program would have to look like this:
macro new-var() {
quasi {
my COMPILING::<$a> = 42
}
};
new-var;
say $a
Note that this won't work today in Rakudo, although you might find something like it can be made to work in 007.
This might not be the answer you are looking for, but macros in Rakudo are currently really broken. At this point in time I can't even remember if it's supposed to work, or if it's a bug in Rakudo -- it's mostly not worth it figuring it out, because most macro things barely work at all.
This is why Carl Mäsak created 007 to experiment with Macro design outside of Rakudo core, with the goal of eventually bringing the lessons learned back to Rakudo and the Perl 6 language design.

Why doesn't this run forever?

I was looking at a rather inconclusive question about whether it is best to use for(;;) or while(1) when you want to make an infinite loop and I saw an interesting solution in C where you can #define "EVER" as a constant equal to ";;" and literally loop for(EVER).
I know defining an extra constant to do this is probably not the best programming practice but purely for educational purposes I wanted to see if this could be done with Perl as well.
I tried to make the Perl equivalent, but it only loops once and then exits the loop.
#!/usr/bin/perl -w
use strict;
use constant EVER => ';;';
for (EVER) {
print "FOREVER!\n";
}
Output:
FOREVER!
Why doesn't this work in perl?
C's pre-processor constants are very different from the constants in most languages.
A normal constant acts like a variable which you can only set once; it has a value which can be passed around in most of the places a variable can be, with some benefits from you and the compiler knowing it won't change. This is the type of constant that Perl's constant pragma gives you. When you pass the constant to the for operator, it just sees it as a string value, and behaves accordingly.
C, however, has a step which runs before the compiler even sees the code, called the pre-processor. This actually manipulates the text of your source code without knowing or caring what most of it means, so can do all sorts of things that you couldn't do in the language itself. In the case of #DEFINE EVER ;;, you are telling the pre-processor to replace every occurrence of EVER with ;;, so that when the actual compiler runs, it only sees for(;;). You could go a step further and define the word forever as for(;;), and it would still work.
As mentioned by Andrew Medico in comments, the closest Perl has to a pre-processor is source filters, and indeed one of the examples in the manual is an emulation of #define. These are actually even more powerful than pre-processor macros, allowing people to write modules like Acme::Bleach (replaces your whole program with whitespace while maintaining functionality) and Lingua::Romana::Perligata (interprets programs written in grammatically correct Latin), as well as more sensible features such as adding keywords and syntax for class and method declarations.
It doesn't run forever because ';;' is an ordinary string, not a preprocessor macro (Perl doesn't have an equivalent of the C preprocessor). As such, for (';;') runs a single time, with $_ set to ';;' that one time.
Andrew Medico mentioned in his comment that you could hack it together with a source filter.
I confirmed this, and here's an example.
use Filter::cpp;
#define EVER ;;
for (EVER) {
print "Forever!\n";
}
Output:
Forever!
Forever!
Forever!
... keeps going ...
I don't think I would recommend doing this, but it is possible.
This is not possible in Perl. However, you can define a subroutine named forever which takes a code block as a parameter and runs it again and again:
#!/usr/bin/perl
use warnings;
use strict;
sub forever (&) {
$_[0]->() while 1
}
forever {
print scalar localtime, "\n";
sleep 1;
};

Comparing Strings in C Macros (for MODULE_LICENSE)

I'd like to be able to ensure I don't accidentally statically link any proprietary modules into the kernel. I was thinking of making MODULE_LICENSE("Proprietary") fail at compile time if MODULE was not defined. (or even better, fail if MODULE_LICENSE("GPL") was not defined...).
But I can't find a good way to compare strings within a macro -- anyone have any good solutions to this?
I don't think you can do this.
The way it's usually done is by defining preprocessor symbols, and comparing their (integer) values:
#define LICENSE_PROPRIETARY 1
#define LICENSE_GPL 2
#define LICENSE_MIT 3
#define MODULE_LICENSE LICENSE_GPL
#if MODULE_LICENSE != LICENSE_GPL
#error "Not GPL, fail fail"
#endif

C\C++ Preprocessor different arg for overloaded macros

I want to realize logging in my project.
I have macro, smth like
__LOG_TRACE(lg, expr,...) LOG_TRACE_STREAM(lg) << expr;
So I want to realize interface for this macro - another macro, but I want to support 2 types:
LOG_TRACE(msg);
LOG_TRACE(my_logger, msg);
I have some global logger, and first macro will write msg using global logger.
Second macro will take my_logger and write msg using it.
I can make it with LOG_TRACE(msg, my_logger); - but it's not good, it's harder to read in code. Order of arguments in __LOG_TRACE is not necessary.
Upd:
I don't mean overloading macros.
Look - for example I can do this
#define LOG_TRACE(...) __LOG_TRACE(__VA_ARGS__, current_active)
Now I can write
LOG_TRACE(msg);
LOG_TRACE(msg, logger);
But I want not msg,logger and logger,msg
Macro overloading is not allowed in C or C++. But there are workarounds. Here's an article that will help you "overload" your macro: http://cplusplus.co.il/2010/08/31/overloading-macros/
If you don't have a variable number of loggers, i recommend you to make a macro for each logger. ex (LOG_TRACE_XML, LOG_TRACE_OUT, LOG_TRACE_TXT). Because simpler is better.
But a better way to do this is to have LOG_TRACE_ERROR/ LOG_TRACE_WARNING/ LOG_TRACE_INFO and manage the way these macros behave using IPC or another macro (SET_MODE(XML/TXT/OUT))
You cannot overload pre-processor macros, your compiler will consider this a redeclaration, rather than an overload, and so only the 2nd will be valid.
You should attempt to name your macros differently, both for readability and because that's the only way you'll get the functionality you want.
Why not make it a function + do and stringify expression macro?
#define DO_AND_RETURN_STRING_EXPR(x) (x,#x)
ov(DO_AND_RETURN_STRING_EXPR(y))
ov(my_logger, DO_AND_RETURN_STRING_EXPR(y))
(note I haven't tested this code).
__VA_ARGS__ is an extension to the current C++ standard, but if you are willing to play with this P99 has a lot of utility macros to achieve what you want. In particular macros that implement conditionals according to the number of arguments they are called.
#define LOG_TRACE(...) \
P99_IF_EQ_1(P99_NARG(__VA_ARGS__)) \
(LOG_TRACE_(my_logger, __VA_ARGS__)) \
(LOG_TRACE_(__VA_ARGS__))
P99 is not really C++ compatible, so you'd have to adapt things a bit.
BTW, identifiers that start with _ and a capital letter or another underscore are reserved by C and C++. Double underscores in general are not allowed for C++ because they could interfere with name mangling. So you'd better chose a different name for your base macro.

Is it possible to define a macro that looks almost like a comment?

I try to make a useful macro for logging. But I find that NSLog and all other sort of macros that carry textual information with them simply distract a lot from the code.
Is there any way to "hack" Xcode in a way that it will interpret something like
/*** do this because of that ***/
as a macro call, which results in calling NSLog, for example? I want those logs to "feel" like comments. Anything else that looks like critical code is just distracting and reduces productivity at the end, and then there's no real benefit from logging what's going on.
Is it possible to define a macro that looks almost like a comment?
Why do you want to make your code less readable?
The answer is no, and that's a good thing.
Is there any way to "hack" Xcode in a way that it will interpret something like
/*** do this because of that ***/
as a macro call…
Probably, but that's useless. All that would do is make the syntax coloring incorrect (coloring this comment as if it were a function call). The compiler (either GCC or Clang) would still see this as the comment that it is.
Making the compiler think it's a function call or macro invocation is what would actually achieve log output at run time, but even if you could do that, it's still a bad idea because you would have a function call or macro invocation disguised as a comment.
If you want your program to log messages, write logging code:
NSLog(#"Do %# because of %#.", foo, bar);
This code is explicitly code that does something at runtime. No mystery. No surprises. That's why it's better.
You can enclose one or more lines of NSLog in curly braces and then use Xcode's folding option to hide them.
Example:
{
NSLog(#"<#label#>");
NSLog(#"<#label#>");
}
when folded look like:
{...}
The braces will also indent the statements when unfolded making them more visually distinct.
I think you should reconsider your use of log statements. If you have as many logs statements as lines of code something is wrong. You should be using the debugger to print most values and messages. If you have that many log statements you reach a point where mistakes in the log statements produce more bugs than the code. You also have a big problem cleaning up the code for release.
Not that I know of (though I may be wrong!)
I think that if you want it to look different, a macro is probably the best that you can hope for - at least it will be highlighted a different color :)