|
Home > Archive > Unix Programming > August 2006 > #define number of digits in UINT_MAX
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
#define number of digits in UINT_MAX
|
|
| A. Farber 2006-08-20, 7:36 am |
| Hello,
I work on a program written in C, which I use on OpenBSD,
but also try to keep it compilable on Linux and Cygwin.
I wonder what would be the most portable way to find out
how many characters are needed to represent an unsigned
integer value - at the compilation time.
On my OpenBSD PC the header /usr/include/sys/limits.h
defines UINT_MAX to be 4294967295, i.e. I'd need
maximal 10 characters for the digits + 1 byte for the
terminating zero:
typedef struct user {
....
unsigned id;
char id_str[10 + 1];
....
} user;
But what about the other architectures (non-i386) and OSes?
I could probably check for
#if UINT_MAX > 4294967295U
..... and here?
Thanks
Alex
--
http://preferans.de
| |
| Maxim Yegorushkin 2006-08-20, 1:21 pm |
| A. Farber wrote:
> I work on a program written in C, which I use on OpenBSD,
> but also try to keep it compilable on Linux and Cygwin.
>
> I wonder what would be the most portable way to find out
> how many characters are needed to represent an unsigned
> integer value - at the compilation time.
>
> On my OpenBSD PC the header /usr/include/sys/limits.h
> defines UINT_MAX to be 4294967295, i.e. I'd need
> maximal 10 characters for the digits + 1 byte for the
> terminating zero:
>
> typedef struct user {
> ....
> unsigned id;
> char id_str[10 + 1];
> ....
> } user;
>
> But what about the other architectures (non-i386) and OSes?
>
> I could probably check for
>
> #if UINT_MAX > 4294967295U
> .... and here?
You can probably find an answer in system headers:
/usr/include/c++/4.1.1/limits (linux)
#define __glibcxx_digits(T) \
(sizeof(T) * __CHAR_BIT__ - __glibcxx_signed (T))
// The fraction 643/2136 approximates log10(2) to 7 significant digits.
#define __glibcxx_digits10(T) \
(__glibcxx_digits (T) * 643 / 2136)
and then:
typedef struct user {
....
unsigned id;
char id_str[__glibcxx_digits10(unsigned) + 1];
....
} user;
You can probably convert the integer to textual form while outputting.
It might be easier to have and handle it in binary form (i.e. as a
variable of an integer type) rather than in textual at all other times.
Why do you need to store it in your appication in textual form while
having a copy in binary?
| |
|
| A. Farber wrote:
> Hello,
>
> I work on a program written in C, which I use on OpenBSD,
> but also try to keep it compilable on Linux and Cygwin.
>
> I wonder what would be the most portable way to find out
> how many characters are needed to represent an unsigned
> integer value - at the compilation time.
>
> On my OpenBSD PC the header /usr/include/sys/limits.h
> defines UINT_MAX to be 4294967295, i.e. I'd need
> maximal 10 characters for the digits + 1 byte for the
> terminating zero:
>
> typedef struct user {
> ....
> unsigned id;
> char id_str[10 + 1];
> ....
> } user;
>
> But what about the other architectures (non-i386) and OSes?
>
> I could probably check for
>
> #if UINT_MAX > 4294967295U
> .... and here?
My first thought was to try to count the characters in the macro
expansion, but I don't think that's possible in the ANSI preprocessor.
Besides, on my system, the unsigned constants are in hex and the signed
constants are in decimal (possibly suffixed by type qualifiers).
The only other way I can think of is by taking the sizeof(unsigned)
which is in a sense the number of digits required for the value in
base-256; then multiplying that by log10(256); add one to get the
ceiling, add one for the possible sign, and truncate:
int digits = sizeof(unsigned)*2.41+2; // 2.41 is approx. log10(256)
>
> Thanks
> Alex
>
> --
> http://preferans.de
| |
| A. Farber 2006-08-20, 1:21 pm |
| Hi Maxim,
Maxim Yegorushkin wrote:
> #define __glibcxx_digits(T) \
> (sizeof(T) * __CHAR_BIT__ - __glibcxx_signed (T))
>
> // The fraction 643/2136 approximates log10(2) to 7 significant digits.
> #define __glibcxx_digits10(T) \
> (__glibcxx_digits (T) * 643 / 2136)
> typedef struct user {
> ....
> unsigned id;
> char id_str[__glibcxx_digits10(unsigned) + 1];
> ....
> } user;
thanks! I've got the meaning of you macro
(__glibcxx_digits gives back the number of bits in a type T,
it's 1 bit less if it is a signed type),
but I'm still struggling with the math... (should
num of bits / num of dec. digits really be equal to log(2) ?)
> You can probably convert the integer to textual form while outputting.
> It might be easier to have and handle it in binary form (i.e. as a
> variable of an integer type) rather than in textual at all other times.
> Why do you need to store it in your appication in textual form while
> having a copy in binary?
My C-program talks to a Macromedia Flash-client using
"application/x-www-form-urlencoded" encoding, so I have
to use strings in my program...
Regards
Alex
--
http://preferans.de
| |
| Maxim Yegorushkin 2006-08-20, 1:21 pm |
|
A. Farber wrote:
> Hi Maxim,
>
> Maxim Yegorushkin wrote:
>
>
> thanks! I've got the meaning of you macro
> (__glibcxx_digits gives back the number of bits in a type T,
> it's 1 bit less if it is a signed type),
Sorry, I actually made an error, the correction:
char id_str[__glibcxx_digits10(unsigned) + 1 + 1];
The macro in fact tells you how many decimal digits can be stored in an
integer without truncating. For unsigned char it is 2, since 3 would
mean you could store at least [0, 999] in unsigned char. That's why +1.
> but I'm still struggling with the math...
So am I today ;)
> (should
> num of bits / num of dec. digits really be equal to log(2) ?)
>
>
> My C-program talks to a Macromedia Flash-client using
> "application/x-www-form-urlencoded" encoding, so I have
> to use strings in my program...
I meant, you could convert an integer to textual form no earlier than
when you pass data to the client. In that routine it would be possible
to preallocate a buffer of sufficiently big size and then snprintf into
the buffer, or get the number of bytes required for the buffer from
snprintf(0,0, fmt), or use something like asprintf which allocates the
buffer for you. (man asprintf on linux says it's available on bsd).
| |
| Keith Thompson 2006-08-20, 7:22 pm |
| "A. Farber" <Alexander.Farber@gmail.com> writes:
> I work on a program written in C, which I use on OpenBSD,
> but also try to keep it compilable on Linux and Cygwin.
>
> I wonder what would be the most portable way to find out
> how many characters are needed to represent an unsigned
> integer value - at the compilation time.
>
> On my OpenBSD PC the header /usr/include/sys/limits.h
> defines UINT_MAX to be 4294967295, i.e. I'd need
> maximal 10 characters for the digits + 1 byte for the
> terminating zero:
>
> typedef struct user {
> ....
> unsigned id;
> char id_str[10 + 1];
> ....
> } user;
>
> But what about the other architectures (non-i386) and OSes?
>
> I could probably check for
>
> #if UINT_MAX > 4294967295U
> .... and here?
A partial solution would be to check for the most common actual values
of UINT_MAX. Something like this:
#if UINT_MAX == 65535U
#define UINT_DIGITS 5
#elif UINT_MAX == 4294967295U
#define UINT_DIGITS 10
#elif UINT_MAX == 18446744073709551615U
#define UINT_DIGITS 20
#else
#error "Unrecognized value for UINT_MAX, can't determine UINT_DIGITS"
#endif
A more exhaustive solution might compare UINT_MAX to 10000U, 100000U,
etc. (I haven't gotten that to work in my very brief attempt.)
It's easy enough to determine the number of digits at run time. If
you can write a C program that generates a small header file, and you
can invoke during your build process, that might also be a solution.
This won't work if you're using a cross-compiler.
I've defined UINT_DIGITS as the number of actual digits in the number,
excluding the trailing '\0'.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
| |
| James Antill 2006-08-21, 7:26 pm |
| On Sun, 20 Aug 2006 04:26:55 -0700, A. Farber wrote:
> Hello,
>
> I work on a program written in C, which I use on OpenBSD,
> but also try to keep it compilable on Linux and Cygwin.
>
> I wonder what would be the most portable way to find out
> how many characters are needed to represent an unsigned
> integer value - at the compilation time.
>
> On my OpenBSD PC the header /usr/include/sys/limits.h
> defines UINT_MAX to be 4294967295, i.e. I'd need
> maximal 10 characters for the digits + 1 byte for the
> terminating zero:
This is how I did it using autoconf...
AC_MSG_CHECKING(for the length of ULONG_MAX as a string)
AC_CACHE_VAL(local_cv_has_ULONG_MAX_len_
sprintf,[
AC_TRY_RUN([
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
int main() {
char buffer[1024 + (CHAR_BIT * sizeof(unsigned long))];
int len;
sprintf(buffer, "%lu", ULONG_MAX);
len = strlen(buffer);
{ FILE *f = fopen("conftestval", "w");
if (!f) exit (1);
fprintf(f, "%d\n", len);
}
return 0;
}],
& #91;local_cv_has_ULONG_MAX_len_sprintf=`
cat conftestval`],
local_cv_has_ULONG_MAX_len_sprintf="nope",
)])
AC_MSG_RESULT($local_cv_has_ULONG_MAX_le
n_sprintf)
case x$local_cv_has_ULONG_MAX_len_sprintf in
xnope) ;;
*) AC_DEFINE_UNQUOTED(ULONG_MAX_LEN, $local_cv_has_ULONG_MAX_len_sprintf)
esac
--
James Antill -- james@and.org
http://www.and.org/and-httpd
| |
| A. Farber 2006-08-22, 7:32 am |
| Hello James,
James Antill wrote:
> int main() {
> char buffer[1024 + (CHAR_BIT * sizeof(unsigned long))];
> int len;
> sprintf(buffer, "%lu", ULONG_MAX);
> len = strlen(buffer);
> { FILE *f = fopen("conftestval", "w");
> if (!f) exit (1);
> fprintf(f, "%d\n", len);
> }
> return 0;
I've noticed that you could have used snprintf there:
len = snprintf(NULL, 0, "%lu", ULONG_MAX);
Regards
Alex
--
http://preferans.de
| |
| Bjorn Reese 2006-08-22, 7:32 am |
| A. Farber wrote:
> I've noticed that you could have used snprintf there:
>
> len = snprintf(NULL, 0, "%lu", ULONG_MAX);
That assumes a C99 compliant snprintf(), which is not available on all
platforms.
I use "sizeof(int) * CHAR_BIT", since I need to store numbers of
different bases.
--
mail1dotstofanetdotdk
|
|
|
|
|