views:

311

answers:

8

I'm writing a program and I have the following problem:

char *tmp;
sprintf (tmp,"%ld",(long)time_stamp_for_file_name);

Could someone explain how much memory allocate for the string tmp.

How many chars are a long variable?

Thank you,

I would appreciate also a link to an exahustive resource on this kind of information.

Thank you

UPDATE:

Using your examples I got the following problem:

root@-[/tmp]$cat test.c

       #include <stdio.h>
       int
       main()
       {
            int len;
            long time=12345678;
            char *tmp;
            len=snprintf(NULL,0,"%ld",time);
            printf ("Lunghezza:di %ld %d\n",time,len);      
            return 0;
       }

root@-[/tmp]$gcc test.c
root@-[/tmp]$./a.out 
Lunghezza:di 12345678 -1
root@-[/tmp]$

So the len result from snprintf is -1, I compiled on Solaris 9 with the standard compiler.

Please help me!

+3  A: 

It depends on how big long is on your system. Assuming a worst case of 64 bits then you need 22 characters max - this allows for 20 digits, a preceding - and a terminating \0. Of course if you're feeling extravagant you could always allow a little extra and make it a nice round number like 32.

Paul R
+4  A: 

It's hard to tell in advance, although I guess you could guesstimate that it'll be at the most 64 bits, and thus "18,446,744,073,709,551,615" should be the largest possible value. That's 2+6*3 = 20 digits, the commas are generally not included. It'd be 21 for a negative number. So, go for 32 bytes as a nice and round size.

Better would be to couple that with using snprintf(), so you don't get a buffer overflow if your estimate is off.

unwind
A: 
How many chars are a long variable?

well, that depends on a few things, how big your sizeof(long) is on your machine? go on, run it.

Anyway, then you can find out how big the number could possibly be, lets pretend its 4 bytes, but it could be more. So, 2^(8 * 4) = 4 294 967 296

That's 10 chars + 1 for the null terminating character.

However, unless you're seriously pressed for memory, allocating something like 255 chars for this is the usual way of doing things.

Salgar
+6  A: 

The number of chars actually used obviously depends on the value: if time_stamp_for_file_name is 0 you only actually need 2 bytes. If there's any doubt, you can use snprintf, which tells you how much space you need:

int len = snprinf(0, 0, "%ld", (long)time_stamp_for_file_name) + 1;
char *tmp = malloc(len);
if (tmp == 0) { /* handle error */ }
snprintf(tmp, len, "%ld", (long)time_stamp_for_file_name);

Beware implementations where snprintf returns -1 for insufficient space, rather than the space required.

As Paul R says, though, you can figure out a fixed upper bound based on the size of long on your implementation. That way you avoid dynamic allocation entirely. For example:

#define LONG_LEN (((sizeof(long)*CHAR_BIT)/3)+2)

(based on the fact that the base-2 log of 10 is greater than 3). That +2 gives you 1 for the minus sign and 1 for the fact that integer division rounds down. You'd need another 1 for the nul terminator.

Or:

#define STRINGIFY(ARG) #ARG
#define EXPAND_AND_STRINGIFY(ARG) STRINGIFY(ARG)

#define VERBOSE_LONG EXPAND_AND_STRINGIFY(LONG_MIN)
#define LONG_LEN sizeof(VERBOSE_LONG)

char tmp[LONG_LEN];
sprintf(tmp, "%ld", (long)time_stamp_for_file_name);

VERBOSE_LONG might be a slightly bigger string than you actually need. On my compiler it's (-2147483647L-1). I'm not sure whether LONG_MIN can expand to something like a hex literal or a compiler intrinsic, but if so then it could be too short, and this trick won't work. It's easy enough to unit-test, though.

If you want a tight upper bound to cover all possibilities within the standard, up to a certain limit, you could try something like this:

#if LONG_MAX <= 2147483647L
    #define LONG_LEN 11
#else
    #if LONG_MAX <= 4294967295L
        #define LONG_LEN 11
    #else
        #if LONG_MAX <= 8589934591L
            ... etc, add more clauses as new architectures are
                     invented with bigger longs
        #endif
    #endif
#endif

But I doubt it's worth it: better just to define it in some kind of portability header and configure it manually for new platforms.

Steve Jessop
I'm pretty sure that there's nothing stopping `LONG_MIN` from evaluating to a compiler intrinsic (eg `__lmin` or something). The macro based on `sizeof(long)` seems conservative, safe and portable.
caf
Yes, the stringify wasn't a very serious suggestion - on any system where you're confident it's correct, you could have just manually counted the characters in the most verbose `long` representation...
Steve Jessop
+6  A: 

If your compiler conforms to C99, you should be able to do:

char *tmp;
int req_bytes = snprintf(NULL, 0, "%ld",(long)time_stamp_for_file_name);
tmp = malloc(req_bytes +1); //add +1 for NULL
if(!tmp) {
    die_horrible_death();
}
if(snprintf(tmp, req_bytes+1, "%ld",(long)time_stamp_for_file_name) != req_bytes) {
    die_horrible_death();
}

Relevant parts of the standard (from the draft document):

  • 7.19.6.5.2: If n is zero, nothing is written, and s may be a null pointer.
  • 7.19.6.5.3: The snprintf function returns the number of characters that would have been written had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred. Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n.

If this is not working, I'm guessing your compiler/libc does not support this part of c99, or you might need to explicitly enable it. Wh I run your example (with gcc version 4.5.0 20100610 (prerelease), Linux 2.6.34-ARCH), I get

$./example
Lunghezza:di 12345678 8

gnud
Important note: The Microsoft Visual C++ Compiler (MSVC) does not conform to C99. I don't know if this particular feature is implemented, but it does *not* officially support the 1999 standard.
Computer Guru
+1  A: 

Octal requires one character per three bits. You print to base of ten which never gives more digits than octal for same number. Therefore, allocate one character for each three bits.

sizeof(long) gives you amount of bytes when compiling. Multiply that by 8 to get bits. Add two before dividing by three so you get ceiling instead of floor. Remember the C strings want a final zero byte to their end, so add one to the result. (Another one for negative, as described in comments).

char tmp[(sizeof(long)*8+2)/3+2];
sprintf (tmp,"%ld",(long)time_stamp_for_file_name);
Cheery
Better to use CHAR_BIT from limits.h instead of 8; there are still a few oddball platforms out there that use byte sizes other than 8.
John Bode
That's crazy info. Could you find me some platforms like that? I figure some PIC platforms might contain other bit-width of a byte. Though at those platforms you are more or less likely writing platform-dependent code anyway.
Cheery
And add 2 not 1 - you need to account for a `-` sign on negative numbers as well as the nul-terminator.
caf
+2  A: 

It takes log210 (~3.32) bits to represent a decimal digit; thus, you can compute the number of digits like so:

#include <limits.h>
#include <math.h>

long time;
double bitsPerDigit = log10(10.0) / log10(2.0); /* or log2(10.0) in C99 */
size_t digits = ceil((sizeof time * (double) CHAR_BIT) / bitsPerDigit);

char *tmp = malloc(digits+2); /* or simply "char tmp[digits+2];" in C99 */

The "+2" accounts for sign and the 0 terminator.

John Bode
A: 

3*sizeof(type)+2 is a safe general rule for the number of bytes needed to format an integer type type as a decimal string, the reason being that 3 is an upper bound on log10(256) and a n-byte integer is n digits in base-256 and thus ceil(log10(256^n))==ceil(n*log10(256)) digits in base 10. The +2 is to account for the terminating NUL byte and possible minus sign if type is very small.

If you want to be pedantic and support DSPs and such with CHAR_BIT!=8 then use 3*sizeof(type)*((CHAR_BIT+7)/8)+2. (Note that for POSIX systems this is irrelevant since POSIX requires UCHAR_MAX==255 and CHAR_BIT==8.)

R..