I want a debug function-macro that works like this:
int myVar = 5;
PRINTVAR(myVar); // macro
// which expands to something like...
print("myVar: ");
println(myVar);
Basically, I want to use the identifier as a string literal as well as a variable.
I'm just getting a bit sick of repeating myself when I want to dump out a whole lot of variables to the stdout.
My silly attempt, which of course doesn't work:
#define PRINT_VAR(x) Serial.print("x: "); Serial.println(x);
Is this possible?
The "stringizing operator" is designed for precisely this case:
#define PRINT_VAR(x) (print(#x ": "), println(x))
Look up the stringifying operator, #, when you use the macro id prefixed with this, it puts it as a string instead of expanding it.
Giving your code example, I don't know if you're talking about C or Java. However, here is I'll do in C :
#define DEBUG(X, ...) fprintf(x, __VA_ARGS__);
And to use it :
DEBUG(srderr, "my error\n");
Related
For example I have a macro:
#define PRINT(int) printf(#int "%d\n",int)
I kinda know what is the result.
But how come #int repersent the whole thing?
I kinda forget this detail. Can anybody kindely give me a hint?
Thanks!
In this context (applied to a parameter reference in a macro definition), the pound sign means to expand this parameter to the literal text of the argument that was passed to the macro.
In this case, if you call PRINT(5) the macro expansion will be printf("5" "%d\n", 5); which will print 5 5; not very useful; however if you call PRINT(5+5) the macro expansion will be printf("5+5" "%d\n", 5+5); which will print 5+5 10, a little less trivial.
This very example is explained in this tutorial on the C preprocessor (which, incidentally, is the first Google hit for c macro pound sign).
"#" can show the name of a variable, it's better to define the macro as this:
#define PRINT(i) printf(#i " = %d\n", i)
and use it like this:
int i = 5;
PRINT(i);
Result shown:
i = 5
That is a bad choice of name for the macro parameter, but harmless (thanks dreamlax).
Basically if i write like so
PRINT(5);
It will be replaced as
printf("5" "%d\n",5);
or
printf("5 %d\n",5);
It is a process called Stringification, #int is replaced with a string consisting of its content, 5 -> "5"
'#' is called a stringize operator.
Stringize operator puts quotes around the parameter passed and returns a string. It is only used in a marco statements that take the arguments.
#include<stdio.h>
#define stringLiteral(sl) #sl
int main()
{
char StringizeOpreator = 'a';
printf(stringLiteral(StringizeOpreator));
return 0;
}
Here the stringLiteral marco takes the formal argument sl and returns #sl. Actual argument passed is StringizeOpreator variable. The return statement #sl has # operator, that puts quotes around the argument like "StringizeOpreator" and returns a string.
So the output of the above program is the name of the actual parameter 'StringizeOpreator' rather than the value stored in the actual parameter passed.
output :
StringizeOperator
...
exitcode 0
To learn more visit this link:
Stringize Operator
I'm trying to create a lookup macro. Using the ternary operator seems to be a very concise way of doing this. Here's what I have so far:
#define SQL_LOOKUP_TABLE(x) (strncmp(x, "int", strlen(x)) == 0) ? "INTEGER" : SQL_LOOKUP_TABLE1(x)
#define SQL_LOOKUP_TABLE1(x) (strncmp(x, "char", strlen(x)) == 0) ? "TEXT" : SQL_LOOKUP_TABLE2(x)
#define SQL_LOOKUP_TABLE2(x) (strncmp(x, "double", strlen(x)) == 0) ? "REAL" : ""
I want to pass in the type as a string in c, and then get the corresponding SQL type back as a string. It works great when I do something like this:
printf("Ternary test: %s\n", SQL_LOOKUP_TABLE("double")); //output "REAL"
What I really want to do, is take this information and build an entire SQL CRUD statement. The problem comes in when I try to build the string inside of another macro. Something like this does not work:
#define BUILD_A_STRING(x) "CREATE TABLE ( " SQL_LOOKUP_TABLE( x )
I get error:
error C2064: term does not evaluate to a function taking 337 arguments
Quick note, this does work(returns "REAL"):
#define BUILD_A_STRING(x) SQL_LOOKUP_TABLE( x )
Any ideas why I can't call the macro inside of another macro and also build a string?
Edit(at the risk of providing TMI):
This is what I really want to do:
typedef struct {
double yomama;
int x;
char shiboopy[100];
} test_data1;
#define EXPAND_AS_CREATE_STATEMENT(type, element, struct_name) SQL_LOOKUP_TABLE( #type) " " # element ", "
#define test_data1_TABLE(ENTRY) \
ENTRY(double, yomama, test_data1) \
ENTRY(int, x, test_data1) \
ENTRY(char, shiboopy, test_data1)
char* create_stmt = "CREATE TABLE test_data1 (" test_data1_TABLE(EXPAND_AS_CREATE_STATEMENT) ");"; \
Basically use an X macro to define a struct's data types and then expand it out into whatever CRUD statements I might need.
Lexical string concatenation is a preprocessor operation. The ternary operator is a runtime operation. When the strings are attempted to be concatenated, the preprocessor will look for adjacent string literals, but will fail to find any because
"CREATE TABLE ( " SQL_LOOKUP_TABLE( x )
is preprocessed to
"CREATE TABLE ( " (strncmp(x, "int", strlen(x)) == 0) ? "INTEGER" : SQL_LOOKUP_TABLE1(x)
and the preprocessor does not know about strncmp, strlen, or the ternary operator.
To do what you want, you'd have to do the conditional stuff when the preprocessor runs. The C preprocessor is too simplistic for that, though, it would require a more sophisticated preprocessor like m4 for that.
The other, unfavorable way to go would be to do the concatenation at runtime with a little overhead involved, obviously.
I recommend you just rethink your design. A hashtable might come in handy: it will work and it is cleaner and more efficient.
I'm interpreting this:
What I really want to do, is take this information and build an entire SQL CRUD statement.
...and this:
This is what I really want to do:
...as overriding this:
I want to pass in the type as a string in c, and then get the corresponding SQL type back as a string.
I don't think you should pass the type in as a C string; that gains you nothing, since all you're doing with that string is passing it right back to a macro (and macros can do nothing with strings). If instead you pass the token to the macro, you can have the C preprocessor itself do the lookup.
Here's what I mean:
#define SQL_LOOKUP_TABLE(x) DB_TYPE_FOR_ ## x
#define DB_TYPE_FOR_double "REAL"
#define DB_TYPE_FOR_int "INTEGER"
#define DB_TYPE_FOR_char "TEXT"
Pass the token to this macro, not the stringified token:
#define EXPAND_AS_CREATE_STATEMENT(type, element, struct_name) \
SQL_LOOKUP_TABLE(type) " " # element ", "
...and this:
"CREATE TABLE test_data1 (" test_data1_TABLE(EXPAND_AS_CREATE_STATEMENT) ");"
...just expands to this:
"CREATE TABLE test_data (" "REAL" " " "yomama" ", " "INTEGER" " " "x" ", " "TEXT" " " "shaboopy" ", " ");"
...which after string literal concatenation is equivalent to:
"CREATE TABLE test_data (REAL yomama, INTEGER x, TEXT shaboopy, );"
No strcmp's, no chains of ternaries, no hashtables required. Now, I'm not sure if your database engine is lazy enough to accept trailing commas in the parameter list, but that's another issue (the simplest resolution would be to add delimiter macro support to your X macro).
#Downvoter' s answer explains the reason of the error you get.
I think it's better to use a function in your case.
something like:
char* build_str(char* type)
{
static char str[80];
char* sql_type_str = SQL_LOOKUP_TABLE(type);
strcat(str, "CREATE TABLE (");
strcat(str,sql_type_str);
/* strcat others params */
return str;
}
Maybe you have to give more details on how you plan to use BUILD_STRING.
So when looking into getting my define macro to work, I found the # and ## macro helpers, and used them to simplify my macro. The key part of the macro sets a variable to a string containing the name of the variable (but not the variable name alone). As a simplified example, let's take a macro called SET(X) that should expand SET(something) into something = "pre_something".
The only way I've found to do it so far is with two macros like #define QUOTE(X) #X and #define SET(X) X = QUOTE(pre_##X). However, using multiple macros seems excessive, and may cause problems with further macro expansion (I think). Is there a cleaner, one-line way of doing the same thing?
#define SET(x) x = "pre_"#x
C does string concatenation at compile time, so two string literals next to each other are concatenated.
"hello " "world" -> "hello world"
When using C preprocessor one can stringify macro argument like this:
#define TO_STRING(x) "a string with " #x
and so when used, the result is as follows:
TO_STRING(test) will expand to: "a string with test"
Is there any way to do the opposite? Get a string literal as an input argument and produce a C identifier? For example:
TO_IDENTIFIER("some_identifier") would expand to: some_identifier
Thank you for your answers.
EDIT: For those wondering what do I need it for:
I wanted to refer to nodes in a scene graph of my 3D engine by string identifiers but at the same time avoid comparing strings in tight loops. So I figured I'll write a simple tool that will run in pre-build step of compilation and search for predefined string - for example ID("something"). Then for every such token it would calculate CRC32 of the string between the parenthesis and generate a header file with #defines containing those numerical identifiers. For example for the string "something" it would be:
#define __CRC32ID_something 0x09DA31FB
Then, generated header file would be included by each cpp file using ID(x) macros. The ID("something") would of course expand to __CRC32ID_something, so in effect what the compiler would see are simple integer identifiers instead of human friendly strings. Of course now I'll simply settle for ID(something) but I thought that using quotes would make more sense - a programmer who doesn't know how the ID macro works can think that something without quotes is a C identifier when in reality such identifier doesn't exist at all.
No, you can't unstringify something.
//unstringify test
enum fruits{apple,pear};
#define IF_WS_COMPARE_SET_ENUM(x) if(ws.compare(L#x)==0)f_ret=x;
fruits enum_from_string(wstring ws)
{
fruits f_ret;
IF_WS_COMPARE_SET_ENUM(apple)
IF_WS_COMPARE_SET_ENUM(pear)
return f_ret;
}
void main()
{
fruits f;
f=enum_from_string(L"apple");
f=enum_from_string(L"pear");
}
You can create an identifier from a string, this operation is called token-pasting in C :
#define paste(n) x##n
int main(){
int paste(n) = 5;
printf("%d" , x5);
}
output : 5
KdPrint(("Enter HelloWDMAddDevice\n"));
What's the reason for doing that?
That is so you can pass an entire argument list to the macro and have it pass it on to a function that takes a variable number of arguments.
I would bet anything that the definition of that macro is:
#if DEBUG /* or something like it */
#define KdPrint(args) (printf args)
#else
#define KdPrint(args) /* empty */
#endif
Or similar to some other function that works just like printf.
If it were defined as printf(args), then you could only pass the single string argument, because an argument to a macro can't contain a comma that isn't inside a nested parenthesis.
It causes everything inside the parens to be treated as a single parameter to the macro. In the example shown, it can allow for varargs types of parameters:
KdPrint(( "My info is %s\n", "my name" ));
As well as
KdPrint(( "fn %s ln %s\n", "my", "name" ));
If the macro in question was not well written using parentheses, it might be necessary because of operator precedence. Take this macro for example:
#define MY_MACRO(a) a * 11
Well, if you did this:
int b = MY_MACRO(1 + 2);
b, instead of being 33 like it should, would actually be replaced with int b = 1 + 2 * 11 which is 23 and not 33. If your macro isn't written like that, though (without parenthesis around the a) then it's unnecessary.
If this is the KdPrint() that you are talking about, then this is because you can use KdPrint() macro with format arguments, and it is not a variable length macro.
For example, you can do:
KdPrint(("The answer is %d\n", 42));
and so on.
For your specific example, I cannot tell you, because I don't know what is XdPrint.
But in a more general case, it is because a macro I just like a search and replace. Suppose you have:
#define MULT(a,b) (a*b)
If you call MULT(1+1, 2+2), it would become 1+1*2+2, and result as 5 instead of 8 as you would expect. Doing MULT((1+1), (2+2)) would gives you the expected result. That is why you need to double the brackets.