Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing variable values within a macro

Tags:

c++

macros

Some time ago, I made this beautiful assert macro for c and c++ programs

#define ASSERT(truthy, message) \
     if (!(truthy)) \
     {\
         cout << message << " on line " << __LINE__ << " in file " << __FILE__ << ". Check was " << #truthy << endl;\
     }

Scatter ASSERT calls throughout your code, and it will warn you whenever the truthy value is not truthy! Very handy during development to remind you of potential mistakes.

ex

ASSERT(filesFound > 0, "Couldn't find any files, check your path!");

When filesFound is 0, the macro will print out

Couldn't find any files, check your path! on line 27 in file openFiles.c. Check was filesFound > 0

Now what I want it to print, to give me even more relevant information, is the value of any variables passed into the truthy parameter. Like this

Couldn't find any files, check your path! on line 27 in file openFiles.c. Check was filesFound > 0, filesFound is 0

This seems lisp-like territory, I wonder, is there any black magic c preprocessing that I can use to evaluate variables and functions to their values, without evaluating the truthy statement?

I assume to be disappointed.

like image 381
Azeirah Avatar asked Sep 25 '15 09:09

Azeirah


People also ask

How do you reference a macro variable?

After a macro variable is created, you typically use the variable by referencing it with an ampersand preceding its name (&variable-name), which is called a macro variable reference. These references perform symbolic substitutions when they resolve to their value. You can use these references anywhere in a SAS program.

How do you assign a macro to a variable value?

The %LET statement is followed by the macro variable name, an equal sign (=), and then the text value to be assigned to the macro variable. Notice that quotation marks are not used. Unlike data set variables, macro variables are neither character nor numeric; they always just store text.

Can macros can have local variables?

Local macro variables are defined within an individual macro. Each macro that you invoke creates its own local symbol table. Local macro variables exist only as long as a particular macro executes. When the macro stops executing, all local macro variables for that macro cease to exist.

How do you resolve a macro variable?

These examples using text expressions show how to assign the text generated by macro LOCATE or assign the value of the macro variable NAME: x=resolve('%locate'); x=resolve('&name'); the name of a DATA step variable whose value is a text expression.


1 Answers

An alternative solution which I've always used is to support varargs in the macro and then force the assert user to specify the relevant message / variables - it's a little bit of extra work each time, but on the plus side you can get exactly the formatting that you want and include information not available in the "truthy" bit, e.g:

#define ASSERT(truthy, message, ...) \
if (!(truthy)) \
{\
    MyAssertHandler(__LINE__, __FILE__, #truthy, message, ##__VA_ARGS__);
}

Then you're handler is just a fairly standard var-arg function that can use e.g. vsnprintf to generate the message and output it, e.g. off the top of my head:

void MyAssertHandler(int line, const char* file, const char* expressionStr, const char* format, ...)
{
    // Note: You probably want to use vsnprintf instead to first generate
    //       the message and then add extra info (line, filename, etc.) to
    //       the actual output 
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);

    // Log to bug database, DebugBreak() if a debugger is attached, etc.
}

usage:

ASSERT(IsBlah(), "BlahBlah: x = %.2f, name = %s", GetX(), GetName());
like image 177
Mark Avatar answered Oct 28 '22 05:10

Mark