458,183 Members | 1,386 Online Need help? Post your question and get tips & solutions from a community of 458,183 IT Pros & Developers. It's quick & easy.

# Howto check value of constants in a macro

 P: n/a Hi, I'd like to define several constants and make sure that all of them are smaller than a given other constant. I thought this could be done by a simple macro. Something like this: #define MAX 999 #define DEF_CHECKED_VAL( name, value) #if (value < MAX) \ #define name MAX \ #else \ #define name value \ #endif So DEF_CHECKED_VAL(test_1, 33) should expand to #define test_1 33 and DEF_CHECKED_VAL(test_2, 1000) should yield #define test_2 999 As you probably know (and I learned today) this doesn't work. The most relevant FAQ to this problems seems to be "10.25 I've got this tricky preprocessing I want to do and I can't figure out a way to do it." Unfortunately writing my own preprocessor isn't really an option and I can't believe that I'm the first one who'd like to implement this functionality. Is there a well-known solution to my problem, or am I doing something fundamentally stupid? Thanks for any help, Rick Nov 23 '05 #1
11 Replies

 P: n/a Richard Meister writes: I'd like to define several constants and make sure that all of them are smaller than a given other constant. I thought this could be done by a simple macro. Something like this: #define MAX 999 #define DEF_CHECKED_VAL( name, value) #if (value < MAX) \ #define name MAX \ #else \ #define name value \ #endif So DEF_CHECKED_VAL(test_1, 33) should expand to #define test_1 33 and DEF_CHECKED_VAL(test_2, 1000) should yield #define test_2 999 I think the #if logic above is opposite your examples, so that the < should be >. Here is one possible solution: #define DEF_CHECKED_VAL(name, value) \ enum { name = (value) < MAX ? (value) : MAX }; -- int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\ \n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\ );while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\ );}return 0;} Nov 23 '05 #2

 P: n/a Ben Pfaff writes: Richard Meister writes: I'd like to define several constants and make sure that all of them are smaller than a given other constant. I thought this could be done by a simple macro. Something like this: #define MAX 999 #define DEF_CHECKED_VAL( name, value) #if (value < MAX) \ #define name MAX \ #else \ #define name value \ #endif So DEF_CHECKED_VAL(test_1, 33) should expand to #define test_1 33 and DEF_CHECKED_VAL(test_2, 1000) should yield #define test_2 999 I think the #if logic above is opposite your examples, so that the < should be >. Here is one possible solution: #define DEF_CHECKED_VAL(name, value) \ enum { name = (value) < MAX ? (value) : MAX }; Oooh, that's clever! If you need something more complex, that can't be expressed with integer values and constant expressions, you can always implement your own *simple* preprocessor. There's no need to write a fully functional C preprocessor, just a program that produces C code as its output. For example, given an input like this: MAX 999 DEF_CHECKED_VAL test_1 33 DEF_CHECKED_VAL test_2 1000 the program could produce the following output: #define test_1 33 #define test_2 999 In your build procedure, you can run your program and generate a header file that's then #included by your C source files. Define whatever syntax and semantics you like for the tranformation; the simpler it is, the easier it will be to implement. (Personally, I'd use Perl for something like this, but it can certainly be done in C.) -- Keith Thompson (The_Other_Keith) ks***@mib.org San Diego Supercomputer Center <*> We must do something. This is something. Therefore, we must do this. Nov 23 '05 #3

 P: n/a Richard Meister wrote: Hi, I'd like to define several constants and make sure that all of them are smaller than a given other constant. I thought this could be done by a simple macro. I use the assert macro for that. #include void assert(scalar expression); -- pete Nov 23 '05 #4

 P: n/a Ben Pfaff wrote (in article <87************@benpfaff.org>): Richard Meister writes: I'd like to define several constants and make sure that all of them are smaller than a given other constant. I thought this could be done by a simple macro. Something like this: #define MAX 999 #define DEF_CHECKED_VAL( name, value) #if (value < MAX) \ #define name MAX \ #else \ #define name value \ #endif So DEF_CHECKED_VAL(test_1, 33) should expand to #define test_1 33 and DEF_CHECKED_VAL(test_2, 1000) should yield #define test_2 999 I think the #if logic above is opposite your examples, so that the < should be >. Here is one possible solution: #define DEF_CHECKED_VAL(name, value) \ enum { name = (value) < MAX ? (value) : MAX }; Wow, that is cool. I didn't think it would really work on first look. :-) -- Randy Howard (2reply remove FOOBAR) "The power of accurate observation is called cynicism by those who have not got it." - George Bernard Shaw Nov 23 '05 #5

 P: n/a Keith Thompson writes: If you need something more complex, that can't be expressed with integer values and constant expressions, you can always implement your own *simple* preprocessor. There's no need to write a fully functional C preprocessor, just a program that produces C code as its output. For example, given an input like this: MAX 999 DEF_CHECKED_VAL test_1 33 DEF_CHECKED_VAL test_2 1000 the program could produce the following output: #define test_1 33 #define test_2 999 Even simpler is to write a C program that takes no input to do it. For example (untested, not compiled, etc.): #include int main (void) { const int max = 999; static const struct { const char *name; int value; } *p, values[] = { {"test_1", 33}, {"test_2", 1000}, }; int n_values = sizeof values / sizeof *values; for (p = values; p < &values[n_values]; p++) { int clamped_value = p->value < max ? p->value : max; printf ("#define %s %d\n", p->name, clamped_value); } return 0; } -- "I hope, some day, to learn to read. It seems to be even harder than writing." --Richard Heathfield Nov 23 '05 #6

 P: n/a In article <43***********@mindspring.com>, pete wrote: Richard Meister wrote: Hi, I'd like to define several constants and make sure that all of them are smaller than a given other constant. I thought this could be done by a simple macro. I use the assert macro for that. #include void assert(scalar expression); If you want to check at compile time, proceed as follows: 0 is a "null pointer constant", and 1 isn't. Therefore "" == 0 is a valid expression and "" == 1 isn't. Also, sizeof ("" == 0) is a valid expression and sizeof ("" == 1) isn't. If you have two constants a and b, then ! (a < b) has a value of 0 if a < b is true and a value of 1 if a < b is false. sizeof ("" == ! (a < b)) is a valid expression if a < b and it is not a valid expression if a >= b. So if you have for example ten constants c0, c1, ..., 9 and you want to check at compile time that each is less than 10, then all you need to do is to write a function static void compiletimechecks (void) { sizeof ("" == ! (c0 < 10)); sizeof ("" == ! (c1 < 10)); ... sizeof ("" == ! (c9 < 10)); } Suitable macros could make this more readable. Nov 23 '05 #7

 P: n/a Christian Bau wrote: In article <43***********@mindspring.com>, pete wrote:Richard Meister wrote:Hi,I'd like to define several constants andmake sure that all of them aresmaller than a given other constant. I thought this could be done by asimple macro.I use the assert macro for that.#include void assert(scalar expression); If you want to check at compile time, proceed as follows: 0 is a "null pointer constant", and 1 isn't. Therefore "" == 0 is a valid expression and "" == 1 isn't. Also, sizeof ("" == 0) is a valid expression and sizeof ("" == 1) isn't. If you have two constants a and b, then ! (a < b) has a value of 0 if a < b is true and a value of 1 if a < b is false. sizeof ("" == ! (a < b)) is a valid expression if a < b and it is not a valid expression if a >= b. So if you have for example ten constants c0, c1, ..., 9 and you want to check at compile time that each is less than 10, then all you need to do is to write a function static void compiletimechecks (void) { sizeof ("" == ! (c0 < 10)); sizeof ("" == ! (c1 < 10)); ... sizeof ("" == ! (c9 < 10)); } Suitable macros could make this more readable. Shiny. However, I like the static char test_c0[10-c0]; trick (seen some time ago in clc) as well. Cheers Michael -- E-Mail: Mine is an /at/ gmx /dot/ de address. Nov 23 '05 #8

 P: n/a In article <3u*************@individual.net>, Michael Mair wrote: Christian Bau wrote: In article <43***********@mindspring.com>, pete wrote:Richard Meister wrote:Hi,I'd like to define several constants andmake sure that all of them aresmaller than a given other constant. I thought this could be done by asimple macro.I use the assert macro for that.#include void assert(scalar expression); If you want to check at compile time, proceed as follows: 0 is a "null pointer constant", and 1 isn't. Therefore "" == 0 is a valid expression and "" == 1 isn't. Also, sizeof ("" == 0) is a valid expression and sizeof ("" == 1) isn't. If you have two constants a and b, then ! (a < b) has a value of 0 if a < b is true and a value of 1 if a < b is false. sizeof ("" == ! (a < b)) is a valid expression if a < b and it is not a valid expression if a >= b. So if you have for example ten constants c0, c1, ..., 9 and you want to check at compile time that each is less than 10, then all you need to do is to write a function static void compiletimechecks (void) { sizeof ("" == ! (c0 < 10)); sizeof ("" == ! (c1 < 10)); ... sizeof ("" == ! (c9 < 10)); } Suitable macros could make this more readable. Shiny. However, I like the static char test_c0[10-c0]; trick (seen some time ago in clc) as well. That has two problems: You can run into problems when c0 is unsigned (for example c0 is 11u, 10 - 11u might be 65535u, and you might allocate a static array of 65535 characters without warning! Second, you will declare one or more static arrays and have to hope that compiler and linker optimise them away. The function above is equivalent to static void compiletimechecks (void) { sizeof (int); sizeof (int); ... sizeof (int); } if it compiles at all and hopefully doesn't generate any code. Nov 23 '05 #9

 P: n/a Keith Thompson wrote: Ben Pfaff writes: Richard Meister writes: .... #define MAX 999 #define DEF_CHECKED_VAL( name, value) #if (value < MAX) \ #define name MAX \ #else \ #define name value \ #endif So DEF_CHECKED_VAL(test_1, 33) should expand to #define test_1 33 and DEF_CHECKED_VAL(test_2, 1000) should yield #define test_2 999 I think the #if logic above is opposite your examples, so that the < should be >. Here is one possible solution: #define DEF_CHECKED_VAL(name, value) \ enum { name = (value) < MAX ? (value) : MAX }; Oooh, that's clever! To expand on the method... I think it's okay when we need just a number, but it won't work for the situation where we require a constant of a specific type. Would these always work as intended: DEF_CHECKED_VAL(test_1, 33u) DEF_CHECKED_VAL(test_2, 33l) ? Also, obviously, enum members could not be used in pp directives: DEF_CHECKED_VAL(test_1, 33) /*...*/ #if test_1 > 32 My answer to the problem would rather be a simple: #define MY_MAX 999 #define CK_MY_MAX(x) ((x) < MY_MAX ? (x) : MY_MAX) #define test_1 CK_MY_MAX(33) #define test_2 CK_MY_MAX(1000) There's only one more word to type per each define. It produces constant expressions, suitable for pp. Is there a situation where constant integer expression could not be substituted for an integer constant? (I don't think so.) -- Stan Tobias mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g` Nov 23 '05 #10

 P: n/a Christian Bau wrote: In article <3u*************@individual.net>, Michael Mair wrote: Christian Bau wrote: > If you want to check at compile time, proceed as follows: > > 0 is a "null pointer constant", and 1 isn't. > > Therefore "" == 0 is a valid expression and "" == 1 isn't. > > Also, sizeof ("" == 0) is a valid expression and sizeof ("" == 1) isn't. > > > If you have two constants a and b, then ! (a < b) has a value of 0 if a > < b is true and a value of 1 if a < b is false. > > sizeof ("" == ! (a < b)) is a valid expression if a < b and it is not a > valid expression if a >= b. > > So if you have for example ten constants c0, c1, ..., 9 and you want to > check at compile time that each is less than 10, then all you need to do > is to write a function > > static void compiletimechecks (void) { > sizeof ("" == ! (c0 < 10)); > sizeof ("" == ! (c1 < 10)); > ... > sizeof ("" == ! (c9 < 10)); Why do we need `sizeof'? Wouldn't this be just enough: "" == ! (c0 < 10); ? (Actually, I'd probably add the cast: (void)("" == ! (c0 < 10)); in order to suppress "code has no effect" warnings.) > } > > Suitable macros could make this more readable. Shiny. However, I like the static char test_c0[10-c0]; trick (seen some time ago in clc) as well. In addtion to what Christian has already written (below), gcc accepts char array; (perhaps not in `-ansi' mode, but we need something practical). That's why I have always coded this like: static char test_c0[(c0 < 10) * 2 - 1]; (which has more chances to fail on any compiler if `c0' is not right). Christian's method might be better, but I havn't checked it yet (I don't want just warnings, I want the whole compiler to bail out). That has two problems: You can run into problems when c0 is unsigned (for example c0 is 11u, 10 - 11u might be 65535u, and you might allocate a static array of 65535 characters without warning! Second, you will declare one or more static arrays and have to hope that compiler and linker optimise them away. The function above is equivalent to [snip] -- Stan Tobias mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g` Nov 23 '05 #11

 P: n/a S.Tobias wrote: Christian Bau wrote:In article <3u*************@individual.net>,Michael Mair wrote:Christian Bau wrote:If you want to check at compile time, proceed as follows:0 is a "null pointer constant", and 1 isn't.Therefore "" == 0 is a valid expression and "" == 1 isn't.Also, sizeof ("" == 0) is a valid expression and sizeof ("" == 1) isn't. If you have two constants a and b, then ! (a < b) has a value of 0 if a< b is true and a value of 1 if a < b is false.sizeof ("" == ! (a < b)) is a valid expression if a < b and it is not avalid expression if a >= b.So if you have for example ten constants c0, c1, ..., 9 and you want tocheck at compile time that each is less than 10, then all you need to dois to write a functionstatic void compiletimechecks (void) { sizeof ("" == ! (c0 < 10)); sizeof ("" == ! (c1 < 10)); ... sizeof ("" == ! (c9 < 10)); Why do we need `sizeof'? Wouldn't this be just enough: "" == ! (c0 < 10); ? (Actually, I'd probably add the cast: (void)("" == ! (c0 < 10)); in order to suppress "code has no effect" warnings.) Hmmm, I'd say because even if the compiler does not optimise at all, sizeof ("" == ! (c0 < 10)); will give you sizeof 0; if the thing compiles (sprinkle with (void) ad libitum). However, "" == !(c0 < 10); might be carried out otherwise, including memory for each and every "". It certainly is unnecessary for every C compiler I worked with or generated code for, though. }Suitable macros could make this more readable.Shiny.However, I like the static char test_c0[10-c0];trick (seen some time ago in clc) as well. In addtion to what Christian has already written (below), gcc accepts char array; (perhaps not in `-ansi' mode, but we need something practical). That's why I have always coded this like: static char test_c0[(c0 < 10) * 2 - 1]; (which has more chances to fail on any compiler if `c0' is not right). Good one :-) Christian's method might be better, but I havn't checked it yet (I don't want just warnings, I want the whole compiler to bail out). It certainly is more elegant. That has two problems: You can run into problems when c0 is unsigned(for example c0 is 11u, 10 - 11u might be 65535u, and you might allocatea static array of 65535 characters without warning! Second, you willdeclare one or more static arrays and have to hope that compiler andlinker optimise them away. The function above is equivalent to True; your solution is better and safer to use in this respect. I only used this for checking exact values (by using a pair of these arrays) at compile time with appropriate casting. Cheers Michael -- E-Mail: Mine is an /at/ gmx /dot/ de address. Nov 23 '05 #12

### This discussion thread is closed

Replies have been disabled for this discussion. 