Solved

Length of Expanded Formatting String

Posted on 2004-09-30
10
270 Views
Last Modified: 2010-04-15
Experts,

I am trying to fill a character array using vsnprintf, but need to know how much space to allocate for the array.  On some platforms vsnprintf returns the length of the expanded string so you can call vsnprintf with the length of the current array, re-allocate to the size of the new string (if necessary) and then call it again with to actually fill the array knowing before hand that there is enough space allocated.  Unfortunately on some unix platforms and windows vsnprintf (_vsnprintf in MS) just returns a -1 if the array is not long enough.  Does anyone know a function that will return the size of an expanded format string?  For example. how long will the resulting string of the following be:
("This string is %d characters long.", nCharacters)

Thanks,
David Johns
0
Comment
Question by:david_johns
  • 5
  • 2
  • 2
  • +1
10 Comments
 
LVL 45

Expert Comment

by:Kent Olsen
ID: 12191936
Hi David,

I'm not aware of any ANSI routine that will return the length of the resultant string without actually doing the conversion, too.

My suggestion is to have a "guaranteed large enough" buffer and strdup() the result.

char Buffer[1000];
int    Length;
char *String;


  Length =  sprintf (Buffer, "This string is %d characters long.", nCharacters);
  String = strdup (Buffer);


Of course, in this example, nCharacters has not been set.
Kent
0
 

Author Comment

by:david_johns
ID: 12192519
I guess I am a bit of a perfectionist on things like this.  I just hate the idea of having to impose a static limit.  One alternative I had thought of is figuring out a way to redirect stdout somewhere where it won't bother me and using vprintf then directing stdout back to the console.  Or perhaps use a vfprintf somehow directed to a memory buffer or something.  I know how to direct stdout to a file, or I could even more easily just send it directly to a temp file using vfprintf, but is there a way to in a sense send the stream to NULL (because I don't actually need the string yet) just so I could get the length?  Spark any ideas?

Thanks,
David
0
 
LVL 45

Accepted Solution

by:
Kent Olsen earned 125 total points
ID: 12193061

You could build your own function to do this.  It's not particularly difficult, but it IS tedious, and definitely a re-inventing of most of the wheel.

On today's systems, memory is cheap.  I keep a 256 character "scratch" buffer in most every task/thread/module that I create simply for formatting message.  The extra memory doesn't hurt a thing and 256 bytes ensures that as long as I'm formatted visual messages the buffer will be sufficiently large.

Of course the ..nprintf() variant ensures that even a generously proportioned buffer that is somehow "too small" doesn't adversely affect the rest of the application.


If you think that it's worth the trouble, get a copy of the printf() source from any of the linux distributions and canibalize it.


Good Luck,
Kent
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 22

Expert Comment

by:grg99
ID: 12193836
How about we all mull over these points:

(1)  printf() is usually used to format text.

(2) the text often, but not always, is going to be displayed on just a few lines, maybe 10 max lines would
cover 99.9% of the cases?

(3) Screen widths and resolutions differ, but it's unlikely that anyone is going to have more than 500 characters per line

(4) Memory is about 12 cents a megabyte these days, and getting cheaper...

(5) So a 10 line buffer, at 500 chars per line, is 5000 bytes, which is 1/200th of a megabyte,
so this printf buffer costs you (transiently) 12 cents/200 or 0.06 cents.

You can't afford to tie up 0.06 cents for a few nanoseconds? :)





0
 
LVL 22

Expert Comment

by:NovaDenizen
ID: 12193898
%d will be longest when you print out the minimal integer value.  It's a fairly safe assumption that this value is (-MAXINT-1),  but I don't know of the best standard name for the minimal integer value.  On my solaris box there is INT32_MIN, INT_LEAST32_MIN, INT_MIN, MIN_INT that all have the same value of -2^31.

Anyway, this minimal value printed out as "%d" will have (ceil(log(-INT_MIN) / log(10.0)) + 1) characters.  For 32-bit twos-complement numbers, this is 11.  The quantity resulting from ceil will be the number of digits, and +1 for the minus sign.
0
 
LVL 45

Expert Comment

by:Kent Olsen
ID: 12193910

Hi grg99,

You were doing so well.  Right up until you injected the "time is money" angle.

:)

0
 
LVL 22

Expert Comment

by:NovaDenizen
ID: 12193965
One way to anticipate the buffer length is to assume worst case and use the maximal length for each %d.  Another way is to calculate the length for each individual int.

If you want to know the length of an arbitrary int for %d, this slow function ought to do the trick:
#include <math.h>

int integer_length(int x) {
   int result = 0;
   if (x < 0) {
        x = -x;
        result = 1;
    }
   while (x >= 1000) {
        x /= 1000;
        result += 3;
   }
   while (x >= 10) {
        x /= 10;
        result++;
    }
    result++;
    return result;
}
0
 
LVL 45

Expert Comment

by:Kent Olsen
ID: 12194068

Hi Nova,

This gets you the length of the display value of an integer, but what if the format specifier is a different size?

The bottom line is that the conversion will have to be parsed and the characters counted, then an ample buffer assigned, and finally the conversion parsed again with character substitution.

A scratch buffer is a lot easier and will certainly result in few "wasted" machine cycles.


Kent
0
 
LVL 22

Expert Comment

by:grg99
ID: 12194418
>You were doing so well.  Right up until you injected the "time is money" angle.

Well, what is specifically wrong with measuring the memory usage in that way?


Waay back in the days of steam-powered computers, I worked on a system that charged you 3 cents for each CPU second, and 0.04 cents for every kiloword-second of core (at least they were 60-bit words).  The maximum amount of core you could request was 20K decimal, so that's 3.8 cents per whole-hog computer second.

If we assume the 12 cents/megabyte memory will last 5 years, that's about 40,000 hours, or 145,000,000 seconds, so a megabyte is costing us 12/145 millionths of a cent per second, call it a tenth of a millionth of a cent per megabyte-second.  Assuming the printf() routine takes oh, say a microsecond (about 5000 instructions on a two-pipe Pentium these days), 5000 bytes costs 1/1000 of 1/200th of a tenth of a millionth of a cent. That's one two-trillionth of a cent per call, or 0.5 x 10^-14 $/call.  

If I got the decimal points right, you could call this routine a million million times for a penny.

0
 
LVL 45

Expert Comment

by:Kent Olsen
ID: 12194593

Hi Grg99,

It was just a bit of tongue-in-cheek humor.  Guess it didn't come off that way.


>Waay back in the days of steam-powered computers, I worked on a system that charged you 3 cents for each CPU second, and 0.04 cents for every kiloword-second of core (at least they were 60-bit words).  The maximum amount of core you could request was 20K decimal, so that's 3.8 cents per whole-hog computer second.

I happen to have a couple of core planes from one of those systems on my desk.  :)  A single plane (and its 128 bytes of storage) is larger and weighs as much as a modern SIMM.  Looking at this in the right light, 1 million of these planes has the equivalent storage as a 128MB SIMM.  Of course, it would take several rooms full of these planes to actually achieve this much storage and several additional rooms of support materials to run these.

But it does make modern memory quite the bargain!


Grg99, my e-mail address is in my profile.  How about sending me a quick note so I can send something your way?  It's related to those old systems, not the boards.

Kent



0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ou…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question