Preprocessor again

1
2
3
4
5
6
7
#define __FS( B, NUM ) static unsigned imax const ZXLV##B = NUM;
#define _FS( B, NUM ) __FS( B, NUM )
#define FS( B, NUM ) _FS( B, NUM )
#define FX( V, B ) FS( B + 1, FF1( V, B ) ) FS( B + 2, FF2( V, B ) ) \
                   FS( B + 3, FF3( V, B ) ) FS( B + 4, FF4( V, B ) ) \
                   FS( B + 5, FF5( V, B ) ) FS( B + 6, FF6( V, B ) ) \
                   FS( B + 7, FF7( V, B ) ) FS( B + 8, FF8( V, B ) ) 

FYI imax is just a define to whatever is the largest number type available, as for FF# etc just define them as 0U for simple testing.
My problem is that the resulting output is not what I'm looking for eg:
1
2
3
4
static unsigned imax const ZXLV1 = 1U;
static unsigned imax const ZXLV2 = 0X3U;
static unsigned imax const ZXLV3 = 0X7U;
/* etc */

FYI I cannot put this in an array because the preprocessor won't let me access it with #if #elif etc. Any help would be welcome.
It would help if you explained what you're trying to do.
Well I need this array of defined bits to test against to find the number of bits to each integer type, the reason I'm doing this is because I'd like to see if it is possible to write a limits.h file WITHOUT using the compiler's own version.

I know that there aren't many uses for this but I curios to know if it is possible to, I've already caught the max/min of each integer so I am trying to compare them against each of these values (without making the compiler/intellisense choke on too many scans). Example:
1
2
3
4
static unsigned short zxCHAR_BIT = (( zxUCHAR_MAX == ZXLV1 ) ? 1 : ((zxUCHAR_MAX == ZXLV2) ? 2 : etc... )))))...
#if zxCHAR_BIT == CHAR_BIT
#error Yippee, it works
#endif 


Edit: The equals would use a #define MACRO( NUM, BIT ) to simplify things.
Edit: Corrected code typo
Last edited on
BTW the current output I'm getting is something like
1
2
static unsigned imax const ZXLV( 0 + 1 ) = 1U;
/* etc */

Edit: I was using this to check the defines came out right:
1
2
3
#if ZXLV[ 7 ] == 0xFFU
#error Yippee it came out right
#endif 
Last edited on
Switched back to an array as I realized there was an alternative way. Instead I have a different problem:
 
1>c:\me\prjs\cpp\zxgui\include\zx\std\limits/all.h(167): error C2099: initializer is not a constant

Input
1
2
3
4
5
6
7
8
9
10
11
12
13
#define XX( V, B, R ) ( ZXLV[ B ] <= V ) + R
#define X1( V, B, R ) XX( V, B, XX( V, B + 1, R ) )
#define X2( V, B, R ) X1( V, B, X1( V, B + 2, R ) )
#define X4( V, B, R ) X2( V, B, X2( V, B + 4, R ) )
#define X8( V, B, R ) X4( V, B, X4( V, B + 8, R ) )
#define _ASTXT( M ) #M
#define ASTXT( M ) _ASTXT( M )
#ifdef llong
#define _X( V ) X8( V, 0, X8( V, 16, 0 ) )
#else
#define _X( V ) X8( V, 0, 0 )
#endif
#define X( V ) ( _X( V ) ) 

Output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
X(0)=( 
1>  ( ZXLV[ 0 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 2 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 2 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 4 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 4 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 4 + 2 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 4 + 2 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 8 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 8 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 8 + 2 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 8 + 2 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 8 + 4 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 8 + 4 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 8 + 4 + 2 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 0 + 8 + 4 + 2 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 2 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 2 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 4 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 4 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 4 + 2 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 4 + 2 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 8 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 8 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 8 + 2 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 8 + 2 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 8 + 4 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 8 + 4 + 1 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 8 + 4 + 2 ] <= zxUCHAR_MAX ) + 
1>  ( ZXLV[ 16 + 8 + 4 + 2 + 1 ] <= zxUCHAR_MAX ) + 0 )

Any ideas?
Edit: I even tried switching to the same initializer of zxUCHAR_MAX, no luck there though.
 
static unsigned short const zxCHAR_BITS  = X( UMAX( char  ) );

Edit: Thought of alternative to ternary operator ( helps deal with compilers that don't support it), input/output updated to match, same error though.
Edit: If I try #define zxCHAR_BITS X( zxUCHAR_MAX ) then it gets past the line but reaches this error instead:
1>c:\me\prjs\cpp\zxgui\include\zx\std\limits/all.h(181): fatal error C1012: unmatched parenthesis : missing ')'
Last edited on
Edit:
Still no responses huh? Either no one has any ideas or everyone is expecting more information, in which case please tell me what I still need to post.
Edit:
I got round the error by using the casting macro in the check, I'll post the code later but for now I'm going to finish pruning errors in reliant code (BTW I'm also writing a custom stdint.h for c89, also post later)
Last edited on
Still no responses huh?
We have lives beyond the forum, you should expect participants to reply when they can, in much the same way you ask questions at your convenience.

to see if it is possible to write a limits.h file WITHOUT using the compiler's own version.
You can't in the way you're doing it, that's why there is a limits/h and stdint.h. You can find the range of the types that are common, but you can't determine system specific types.

The way to do it is the way the GNU AutoTools do it. They generate a series of programs that test if the code will compile and what the output is. That way they can reliably tell if the system has a long long for example. On the VAX, there are 4 floating point types. You can't detect the existence of these types using macros. You're also assuming 8 bit bytes and 2s compliment signed numbers ...
1
2
3
4
5
6
7
8
#define MB1(  T, B )  _MB(  T, B ) + _MB(  T, B + 1 )
#define MB2(  T, B )  MB1(  T, B ) + MB1(  T, B + 2 )
#define MB4(  T, B )  MB2(  T, B ) + MB2(  T, B + 4 )
#define MB8(  T, B )  MB4(  T, B ) + MB4(  T, B + 8 )
#define MB16( T, B )  MB8(  T, B ) + MB8(  T, B + 16 )
#define MB(   T, B ) (MB16( T, B ) + MB16( T, B + 32 ))
static short const zxIMAX_BITS  = MB( imax, 0 );
static short const zxCHAR_BITS  = MB( char, 0 );

Now tell me I can't, Intellisense & divine inspiration prove you wrong.
Next on the agenda is float,double and long double.

Edit: I don't quite think you're getting the point of this:
1) Satisfies curiosity
2) Helpful for force defining stuff the compiler's limits.h missed
3) Adds new defines like INT_BIT which can actually be rather helpful in applications designed to hook into other applications or debug the system as a whole
4) Enables developer to focus more on the application then making workarounds for incomplete std files or lack of compiler support for something.
5) I'm NOT assuming 8 bit bytes, I am merely providing a check for my current environment which was removed once I got the right macro.

As for the lives of their own thing well that's fair enough I just thought the forum would have enough users that at least 1 would have the time to respond.
Last edited on
Any such solution only works for:
1. integral types that your compiler supports (no support for floating point types)
2. has 8 bit bytes
3. has 2s compliment signed numbers

If that meets your criteria, then that's good enough for you (if it works).
2. has 8 bit bytes
What makes you think this is true? Where in the code I provided does it explicitly state I'm relying on 8 bits? If you are referring to MB8 then you clearly do not understand the code I have provided, on another note if you know of a compiler that does other bit sizes then please let me know so that I may test on that also.
static unsigned short zxCHAR_BIT = (( zxUCHAR_MAX == ZXLV1 ) ? 1 : ((zxUCHAR_MAX == ZXLV2) ? 2 : etc... )))))...
#if zxCHAR_BIT == CHAR_BIT
Wot de faq. There's no way this will ever work. The preprocessor has no knowledge about anything not stated in preprocessor directives, because it's an initial pass before the parser (hence why it's called "preprocessor").
For example:
1
2
3
4
5
6
7
8
static const unsigned test = 42;

#if test == 42
#error Never triggered.
#endif

int main(){
}
The preprocessor also doesn't have arrays.

If I suffered some brain damage that made me really want to do this, I might try it with template metaprogramming, which at least has more powerful facilities than the preprocessor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Assumes: ~0 is the largest value for any unsigned type.
//Assumes: Explicitly casting an integer to a smaller type keeps the low bits intact.
//Assumes: N for CountBits<N> is an unsigned integer type.
#include <iostream>

typedef unsigned long long biggest_t;

template <biggest_t a, unsigned b>
struct CountDownUp{
	static const unsigned RES = CountDownUp<a>>1, b+1>::RES;
};

template <unsigned b>
struct CountDownUp<0, b>{
	static const unsigned RES = b;
};

template <typename N>
struct CountBits{
	static const unsigned RES = CountDownUp<(N)~(N)0, 0>::RES;
};

int main(){
	std::cout <<CountBits<unsigned char>::RES<<std::endl;
	std::cout <<CountBits<unsigned short>::RES<<std::endl;
	std::cout <<CountBits<unsigned>::RES<<std::endl;
	std::cout <<CountBits<unsigned long long>::RES<<std::endl;
}
Last edited on
I actually found a better method that relies on the binary of a value given, unfortunately I still haven't found a way for the preprocessor to find those values without the original limits.h being included.
1
2
3
4
5
6
7
8
#define ZX__MB(  V, B )((V >> (B)) != 0)
#define ZX_MB1(  V, B )  ZX__MB(  V, B ) + ZX__MB(  V, B + 1 )
#define ZX_MB2(  V, B )  ZX_MB1(  V, B ) + ZX_MB1(  V, B + 2 )
#define ZX_MB4(  V, B )  ZX_MB2(  V, B ) + ZX_MB2(  V, B + 4 )
#define ZX_MB8(  V, B )  ZX_MB4(  V, B ) + ZX_MB4(  V, B + 8 )
#define ZX_MB16( V, B )  ZX_MB8(  V, B ) + ZX_MB8(  V, B + 16 )
#define ZX_MB(   V )   ( ZX_MB16( V, 0 ) + ZX_MB16( V, 32 ) )
#define ZXCHAR_BITS ZX_MB( UCHAR_MAX ) 
Topic archived. No new replies allowed.