0

Please go through.

#define _VERSION_ 1.4
#define DEFAULT_NETWORK_TOKEN_KEY { 3, 6, 5, 100}

// I can't change the above macros but below

#define STR_VALUE(arg)      #arg
#define FUNCTION_NAME(name) STR_VALUE(name\r)
#define TEST_FUNC      #AP started v _VERSION_
#define TEST_FUNC_NAME FUNCTION_NAME(TEST_FUNC)

#define QUOTE_X(t)#t
#define QUOTE(t)QUOTE_X(t)
#define ABC 100 //{ 3, 6, 5, 100}
#define MYSTR "The value of ABC is"     

const uint8 startMsg[] =  MYSTR " " QUOTE(ABC);

results: The value of ABC is 100

const uint8 startMsg[] =  TEST_FUNC_NAME;

results: #AP started v 1.4 (Carriage return) // I also want to remove the space between v and 1.4

I want

const uint8 startMsg[] = ?? ;

Should result #AP started [3.6.5.100] v1.4 (Carriage return) or #AP started [3,6,5,100] v1.4 (Carriage return) or similar.

I am working on an SOC chip and need to show this in the startup. Urgent. :)

------ Answer to the question is ------

#define NETTOKENKEY(a,b,c,d)  "[" #a "." #b "." #c "." #d "]"
#define GENNETTOKENKEY(z)    NETTOKENKEY(z) 

#define STRINGIZER(arg)     #arg
#define STR_VALUE(arg)      STRINGIZER(arg)
#define AP_VERSION_STR      "#AP started v" STR_VALUE(_VERSION_)



#define AP_NETVERSION_STR   "#AP started " \
                            GENNETTOKENKEY(DEFAULT_NETWORK_TOKEN_KEY_VALUES) \
                            " v" STR_VALUE(_VERSION_) **"\r"**

const uint8 startMsg[] = AP_NETVERSION_STR ;
Rick2047
  • 1,565
  • 7
  • 24
  • 35
  • specifically, what is "show this in the startup". Are you running and communicating? If so, just do it at runtime. Is someone loading your hex file and looking for a specific spot in memory where this magical string must be stored in a specific format? If so, then preprocessor is your only solution (AFAIK), and you'll have to get a little more verbose to accomplish what you've shown above. – Josh Petitt Jul 27 '12 at 15:04
  • Thank you all for the effort. However still looking for learning more. – Rick2047 Jul 27 '12 at 15:43

4 Answers4

2

The C Preprocessor is a fairly simple-minded text substitution program, and I don't think it is going to be able to do what you need and produce compile-time constant strings if it is absolutely impossible to change the DEFAULT_NETWORK_TOKEN_KEY macro.

Transforming the 'array' notation is particularly difficult — in fact, the precondition of not changing the array defining macro probably means it is impossible.

If it is possible to define new macros and redefine DEFAULT_NETWORK_TOKEN_KEY so that it produces the same value as it always did, then you can get to the result you want.

To illustrate, note that you can write:

#define x             { 3, 45, 5, 49}
#define f4(a,b,c,d)   #a " - " #b ":" #c "/" #d
#define y(z)          f4(z)

y(x)

When pre-processed, that produces:

"{ 3" " - " "45" ":" "5" "/" "49}"

Note that the braces are parts of the argument strings. Now, if you can do:

#define DEFAULT_NETWORK_TOKEN_KEY_VALUES 3, 6, 5, 100
#define DEFAULT_NETWORK_TOKEN_KEY { DEFAULT_NETWORK_TOKEN_KEY_VALUES}

(where I'm preserving your asymmetric spacing, though I don't think that's really necessary), then you can use:

#define NETTOKENKEY(a,b,c,d)  "[" #a "." #b "." #c "." #d "]"
#define GENNETTOKENKEY(z)    NETTOKENKEY(z)

GENNETTOKENKEY(DEFAULT_NETWORK_TOKEN_KEY_VALUES)

to get the string "[3.6.5.100]" (for the values in my example).

Getting rid of the space between the v and the 1.4 is relatively easy:

#define STRINGIZER(arg)     #arg
#define STR_VALUE(arg)      STRINGIZER(arg)
#define AP_VERSION_STR      "#AP started v" STR_VALUE(_VERSION_)

AP_VERSION_STR

Piecing these together yields:

#define AP_NETVERSION_STR   "#AP started " \
                            GENNETTOKENKEY(DEFAULT_NETWORK_TOKEN_KEY_VALUES) \
                            " v" STR_VALUE(_VERSION_)

static const char version[] = AP_NETVERSION_STR;

If you want a '\r' on the end, add "\r" to the end of the AP_NETVERSION_STR macro definition. String concatenation is very useful!

But, this is predicated on being able to 'change' the definition of DEFAULT_NETWORK_TOKEN_KEY so that it is amenable to being formatted like this. Without that change, I don't think you can do it.


Testing is necessary!

#define _VERSION_ 1.4
#define DEFAULT_NETWORK_TOKEN_KEY_VALUES 3, 6, 5, 100
#define DEFAULT_NETWORK_TOKEN_KEY { DEFAULT_NETWORK_TOKEN_KEY_VALUES}

#define NETTOKENKEY(a,b,c,d)  "[" #a "." #b "." #c "." #d "]"
#define GENNETTOKENKEY(z)    NETTOKENKEY(z)

GENNETTOKENKEY(DEFAULT_NETWORK_TOKEN_KEY_VALUES)

#define STRINGIZER(arg)     #arg
#define STR_VALUE(arg)      STRINGIZER(arg)
#define AP_VERSION_STR      "#AP started v" STR_VALUE(_VERSION_)

AP_VERSION_STR

#define AP_NETVERSION_STR   "#AP started " \
                            GENNETTOKENKEY(DEFAULT_NETWORK_TOKEN_KEY_VALUES) \
                            " v" STR_VALUE(_VERSION_)

AP_NETVERSION_STR

When run through gcc -E, the mildly sanitized output (blank lines and #line controls removed) is what we need:

"[" "3" "." "6" "." "5" "." "100" "]"

"#AP started v" "1.4"

"#AP started " "[" "3" "." "6" "." "5" "." "100" "]" " v" "1.4"
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Yep, I'd even suggest (in preprocessor land) making separate #defines for each of the octets, then you can have to choice whether to cat them together with , to make an array, or with . to make some human readable sequence of characters we generally recognize as an IPv4 address. – Josh Petitt Jul 27 '12 at 15:07
  • @JoshPetitt: once we've broken the taboo on changing `DEFAULT_NETWORK_TOKEN_KEY`, there are all sorts of possibilities. And yes, it might well be sensible to build the list from separate components. Until that taboo is broken, I don't think the preprocessor can help. – Jonathan Leffler Jul 27 '12 at 15:15
  • I am working on it .. seems will be the answer. "#AP started" then the version and token can come anywhere and (Carriage return) at last. I got #AP started v 1.4 [3.6.5.100] till now the space is still not going. trying, – Rick2047 Jul 27 '12 at 15:28
  • Worked like a magic. #define NETTOKENKEY(a,b,c,d) "[" #a "." #b "." #c "." #d "]" #define GENNETTOKENKEY(z) NETTOKENKEY(z) #define STRINGIZER(arg) #arg #define STR_VALUE(arg) STRINGIZER(arg) #define AP_VERSION_STR "#AP started v" STR_VALUE(_VERSION_) #define AP_NETVERSION_STR "#AP started " \ GENNETTOKENKEY(DEFAULT_NETWORK_TOKEN_KEY_VALUES) \ " v" STR_VALUE(_VERSION_) const uint8 startMsg[] = AP_NETVERSION_STR ; – Rick2047 Jul 27 '12 at 15:37
  • @JonathanLeffler, I see what you mean. In this case, I'd probably define two #defines with a comment to "edit both of these". Ugly, but would solve the problem. BTW, could you give me a +1 for link to stringify. My current rep scares me a little :-) – Josh Petitt Jul 27 '12 at 15:38
  • @Jonathan Leffler, After a loooooooooong time I could accept an answer. Ppl were scaring me with a down vote. I couldnt help it. If I did not find correct or even near answer; what wud I do. – Rick2047 Jul 27 '12 at 15:42
  • I also could do till /* #define STR_VALUE(arg) #arg #define FUNCTION_NAME(name) STR_VALUE(name\r) #define NETTOKENKEY(a,b,c,d) [a.b.c.d] #define GENNETTOKENKEY(z) NETTOKENKEY(z) #define TEST_FUNC #AP started v _VERSION_ GENNETTOKENKEY(DEFAULT_NETWORK_TOKEN_KEY_VALUES)// DEFAULT_NETWORK_TOKEN_KEY #define TEST_FUNC_NAME FUNCTION_NAME(TEST_FUNC) */ only. With space between v and 1.4 : ) a smile with space to the world. – Rick2047 Jul 27 '12 at 15:44
1

You better have to use a Preprocessor Data structure as provided by Boost.Preprocessor. All the macros there work in standard C89.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Joel Falcou
  • 6,247
  • 1
  • 17
  • 34
1

why to use macro if you can:

uint arr[] = DEFAULT_NETWORK_TOKEN_KEY;
float v = VERSION;

sprintf(buffer, "#AP started [%u.%u.%u.%u] v%f", arr[0], arr[1], arr[2], arr[3], v); 
René Kolařík
  • 1,244
  • 1
  • 10
  • 18
  • This is the best solution if just printing the data at runtime. (If the OP needs it as a const string in the compiled object, then another solution would be needed) – Josh Petitt Jul 27 '12 at 15:02
  • If it is a piece of hardware with 4KB RAM (see the comment to Joel Falcou's answer), `sprintf()` is probably not going to be an option. – Jonathan Leffler Jul 27 '12 at 15:06
  • I don't want to use sprintf. Its heavy for me. But for startup it might do. Will see if I've space. – Rick2047 Jul 27 '12 at 15:07
  • @JonathanLeffler, if you use a stripped down lib with very simple formatting (i.e. floats are left out, along with some of the more exotic formatting options), he may be able to use it. If this is the only use in the whole program, then it is probably a waste. – Josh Petitt Jul 27 '12 at 15:08
  • Ok, i understand, although i still think there are better tools for this than preprocessor. If you have at least printf, you can print it. If it is bare metal, i expect you have at least your own print function and so (because if you define array x[] = DEFAULT_NETWORK_TOKEN_KEY; )you know location of that numbers in memory and again can print them (with help of your 'to_str'). – René Kolařík Jul 27 '12 at 15:25
1

Read about the # and ## in the C preprocessor. You are putting alot of wrapper around something pretty easy

http://gcc.gnu.org/onlinedocs/cpp/Stringification.html

BTW, AFAIK you will not be able to use the preprocessor to turn your {} into []

Josh Petitt
  • 9,371
  • 12
  • 56
  • 104