Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Determine size of char array to convert numbers with the preprocessor

I’m facing this simple "problem" literally every day and don’t yet have a good solution for it:

char text[STRING_LENGTH + 1] = ""; 
int32_t number = -12312313; 
itoa(number, text, 10); //or sprintf(text, "%d", number);

How do I determine STRING_LENGTH in the preprocessor? STRING_LENGTH should be the maximum length, the type to convert could produce. In my case int32_t => 11.
Surely, I could do something like this:

#define INT32_STRING_LENGTH 11
#define UINT32_STRING_LENGTH 10
//...

but it seems like there should already be a solution to this out there.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

It’s also an option to use snprintf in that case, but that would calculate the length while the application is already running. There’s really no need to do this while running (if you have some spare-bytes):

int32_t number = -12312313; 
char text[snprintf(NULL, 0, "%d", number) + 1];
snprintf(text, sizeof(name), "%d", number);

Maybe there’s a solution using "%d", "%lu", …?

Please correct me, if I’m wrong with anything I mentioned here.

Thanks in advance!

>Solution :

The GNU Portability Library has an amazing single header intprops part which has some amazing code available from github/coreutils/gnulib/intprops.h. The header contains INT_BUFSIZE_BOUND and INT_STRLEN_BOUND:

/* Bound on buffer size needed to represent an integer type or expression T,
   including the terminating null.  T must not be a bit-field expression.  */
#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)

The documentation with usage example is available in the documentation https://www.gnu.org/software/gnulib/manual/html_node/Integer-Bounds.html :

INT_BUFSIZE_BOUND (t) is an integer constant expression that is a
bound on the size of the string representing an integer type or
expression t in decimal notation, including the terminating null
character and any leading – character. For example, if
INT_BUFSIZE_BOUND (int) is 12, any value of type int can be
represented in 12 bytes or less, including the terminating null. The
bound is not necessarily tight.

Example usage:

#include <intprops.h>
#include <stdio.h>
int
int_strlen (int i)
{
  char buf[INT_BUFSIZE_BOUND (int)];
  return sprintf (buf, "%d", i);
}

Note that the header is under GNU Lesser General Public License. Remember to copy the header with license and distribute your software with some contribution and license. Then just:

int32_t number = -12312313; 
char text[INT_BUFSIZE_BOUND(int32_t)];
// or    [INT_BUFSIZE_BOUND(-12312313)];
sprintf(text, "%"PRId32, number);

Note that %d may be invalid for int32_t. Use standard PRId32 from inttypes.h.


The heart of the implementation is this nice function, that can be used to basically calculate log10 of a number as a constant expression:

/* Bound on length of the string representing an unsigned integer
   value representable in B bits.  log10 (2.0) < 146/485.  The
   smallest value of B where this bound is not tight is 2621.  */
#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485)

So basically to get maximum string length, get maximum value for that type, calculate * 146 + 484) / 485) of the maximum value, add +1 for minus sign and add +1 for zero terminating byte – that’s the number of bytes that you need.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading