Board index » cppbuilder » Re: std::string S; --> How S.sprintf ?

Re: std::string S; --> How S.sprintf ?


2005-03-02 04:57:08 PM
cppbuilder51
On Sun, 31 Oct 2004 08:50:57 +0100, XXXX@XXXXX.COM (Thomas Maeder
[TeamB]) wrote:
Quote
<Kos>writes:

>What is the std:string equivalent of AnsiString's sprintf function?
>
>ie
>int i =123;
>AnsiString aS;
>aS.sprintf("Hello %d",i);
>
>
>How to implement the following
>int i =123;
>string S;
>S.sprintf("Hello %d",i); //<--- How ?

std::ostringstream os;
if (os << "Hello " << i)
{
std::string S(os.str());
// use S here
}
else
// conversion failed (very unlikely)
This works fine if you know where to put in the values. But I have to
process Text I get, containing format specifiers for sprintf at random
positions.
 
 

Re:Re: std::string S; --> How S.sprintf ?

"Matthias Bäßler" < XXXX@XXXXX.COM >wrote in message
Quote
This works fine if you know where to put in the values. But I
have to process Text I get, containing format specifiers for
sprintf at random positions.
There is no direct equivilent of AnsiString::sprintf() for std::string().
You will just have to call the generic snprintf() function twice - once to
calculate the length of the string needed, then size the string and call
snprintf() again to fill in the string's memory. For example:
#include <stdio.h>
int i =123;
std::string s;
int size = snprintf(NULL, 0, "Hello %d", i);
s.resize(size);
snprintf(&s[0], size, "Hello %d", i);
As you can see, you would have to specify the formatting parameters twice.
If you do not want to do that, then you can wrap the operations into a
function and use vsnprintf() instead:
#include <stdio.h>
#include <stdarg.h>
void __cdecl string_sprintf(std::string &s, const char* format, ...)
{
va_list ap;
va_start(ap, format);
int size = vsnprintf(NULL, 0, format, ap);
s.resize(size);
vsnprintf(&s[0], size, format, ap);
va_end(ap);
}
int i =123;
std::string s;
string_snprintf(s, "Hello %d", i);
Gambit
 

Re:Re: std::string S; --> How S.sprintf ?

"Matthias Bäßler" < XXXX@XXXXX.COM >wrote in message
Quote
On Sun, 31 Oct 2004 08:50:57 +0100, XXXX@XXXXX.COM (Thomas Maeder
[TeamB]) wrote:

><Kos>writes:
>
>>What is the std:string equivalent of AnsiString's sprintf function?
>>
>>ie
>>int i =123;
>>AnsiString aS;
>>aS.sprintf("Hello %d",i);
>>
>>
>>How to implement the following
>>int i =123;
>>string S;
>>S.sprintf("Hello %d",i); //<--- How ?
>
>std::ostringstream os;
>if (os << "Hello " << i)
>{
>std::string S(os.str());
>// use S here
>}
>else
>// conversion failed (very unlikely)

This works fine if you know where to put in the values. But I have to
process Text I get, containing format specifiers for sprintf at random
positions.
Have you looked at the Boost format function?
- Arnie
 

{smallsort}

Re:Re: std::string S; --> How S.sprintf ?

Remy Lebeau (TeamB) < XXXX@XXXXX.COM >wrote:
Quote
"Matthias Bäßler" < XXXX@XXXXX.COM >wrote in message
news: XXXX@XXXXX.COM ...

>This works fine if you know where to put in the values. But I
>have to process Text I get, containing format specifiers for
>sprintf at random positions.

There is no direct equivilent of AnsiString::sprintf() for std::string().
You will just have to call the generic snprintf() function twice - once to
calculate the length of the string needed, then size the string and call
snprintf() again to fill in the string's memory. For example:

#include <stdio.h>

int i =123;
std::string s;

int size = snprintf(NULL, 0, "Hello %d", i);
s.resize(size);
snprintf(&s[0], size, "Hello %d", i);
Note that this invokes undefined behaviour.
Strings don't guarantee that their data is stored
in an array internally. If you need to do this,
use a vector.
Of course, that' is a PITA, which is why I would
look at boots's format lib if I needed this.
Quote
[...]
Gambit
Schobi
--
XXXX@XXXXX.COM is never read
I'm Schobi at suespammers dot org
"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
 

Re:Re: std::string S; --> How S.sprintf ?

"Hendrik Schober" < XXXX@XXXXX.COM >wrote in message
Quote
Note that this invokes undefined behaviour.
No, it doesn't. The behavior is defined.
Quote
Strings don't guarantee that their data is stored
in an array internally.
Yes, they do. The memory for the characters has to be contigious.
Otherwise c_str() would not work, and the string data could not be used with
non-STL null-terminated string operations. By using the '[]' operator with
the '&' operator, the example is retreiving the address of the memory for
the actual characters, regardless of how the string is storing that memory.
The memory has to exist somewhere, and be large enough to hold all of the
characters contigiously.
Quote
If you need to do this, use a vector.
A vector, on the other hand, does NOT guarantee that the elements are in a
contigious array. That is a common implementation, but not a requirement.
The only requirement is that the elements be indexable. That does not
necesarily mean contigious.
Gambit
 

Re:Re: std::string S; --> How S.sprintf ?

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
A vector, on the other hand, does NOT guarantee that the elements are in a
contigious array. That is a common implementation, but not a requirement.
The only requirement is that the elements be indexable. That does not
necesarily mean contigious.
I don't believe there are any implementations where this is not
true. I've also heard that it will be specified in the next standard.
 

Re:Re: std::string S; --> How S.sprintf ?

"Remy Lebeau \(TeamB\)" < XXXX@XXXXX.COM >wrote:
Quote
A vector, on the other hand, does NOT guarantee that the elements are in a
contigious array.
_Did_ not. This was so obviously not what people expected that the
standard was amended.
Happily, the vendors were among those who expected vector data to be
contiguous. No known implementation was ever found that didn't do this.
Some early string implementations didn't have contiguous data, though
the requirement for c_str() to return a pointer to contiguous data
rather blew that idea away. However, it is never safe to write into the
c_str() pointer, since it is a char const*. A Copy-on-write
implementation of std::string would produce interesting bugs.
(Though Copy-on-write is sufficiently difficult to get right even when
used correctly that vendors are moving away from it.)
Alan Bellingham
--
Me <url:mailto: XXXX@XXXXX.COM ><url:www.doughnut.demon.co.uk/>
ACCU - C, C++ and Java programming <url:accu.org/>
The 2004 Discworld Convention <url:dwcon.org/>
 

Re:Re: std::string S; --> How S.sprintf ?

Remy Lebeau (TeamB) < XXXX@XXXXX.COM >wrote:
Quote
"Hendrik Schober" < XXXX@XXXXX.COM >wrote in message
news:42397c66$ XXXX@XXXXX.COM ...

>Note that this invokes undefined behaviour.

No, it doesn't. The behavior is defined.

>Strings don't guarantee that their data is stored
>in an array internally.

Yes, they do. The memory for the characters has to be contigious.
This is news to me. So far, I always heard
the opposite. Do you happen to have any
references for that?
I thought that this still holds:
www.google.com/groups
Quote
Otherwise c_str() would not work, and the string data could not be used with
non-STL null-terminated string operations. [...]
<quote>
21.3.6 [lib.string.ops]
const charT* c_str() const;
Returns: A pointer to the initial element of an array of length size() + 1
whose first size() elements equal the corresponding elements of the
string controlled by *this and whose last element is a null character
specified by charT().
</quote>
Note the bit where it says "whose first size()
elements equal the corresponding elements of
the string". Nowhere does it say this function
returnes a pointer to the data that the string
uses internally.
Quote
A vector, on the other hand, does NOT guarantee that the elements are in a
contigious array. That is a common implementation, but not a requirement.
The only requirement is that the elements be indexable. That does not
necesarily mean contigious.
While the original std doc did not require
'std::vector' to store its elements in a
contigious array, all who worked on that
part of the doc agreed that this was a pure
oversight. This included all major/known
STL providers, none of which implemented it
otherwise. (Which is why it was always safe
to assume that.)
Consequently, TC1 changed the std to require
'std::vector' to store it's elements in a
contigious array.
Quote
Gambit
--
XXXX@XXXXX.COM is never read
I'm Schobi at suespammers dot org
"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
 

Re:Re: std::string S; --> How S.sprintf ?

"Hendrik Schober" < XXXX@XXXXX.COM >wrote:
[std::string::c_str()]
Quote
Note the bit where it says "whose first size()
elements equal the corresponding elements of
the string". Nowhere does it say this function
returnes a pointer to the data that the string
uses internally.
Indeed.
The interesting part of the standardese is that c_str() may invalidate
&s[0] (21.3/5), which is effectively stating that c_str() may cause a
memory reallocation. This may be because the string has a contiguous
memory block insufficiently large enough to append the terminating null,
or it may be that it's coalescing a number of substrings into one chunk.
I suspect that the vast majority of implementations _will_ actually
return &s[0] for c_str() (making sure s[size()] is null), simply because
c_str() is used so frequently.
snprintf(&s[0], size, "Hello %d", i);
is sufficiently dangerous though that I'd take the programmer out and
shoot him, as a service to my fellows. Sorry, Gambit.
(And don't point that red-eyed glare in my direction, please.)
Alan Bellingham
--
ACCU Conference 2005 - 20-23 April, Randolph Hotel, Oxford, UK
 

Re:Re: std::string S; --> How S.sprintf ?

Side comment:
Quote
The interesting part of the standardese is that c_str()
may invalidate &s[0] (21.3/5), which is effectively stating
that c_str() may cause a memory reallocation. This may
be because the string has a contiguous ...
Or it could be that the STL designer, having been beaten up once too
often by marketing types over people who run into trouble when
misusing his products. then allocates a buffer different from that
which holds the instance' internal data, this buffer to be used
exclusively as the c_str() return value.
. Ed
Quote
Alan Bellingham wrote in message
news: XXXX@XXXXX.COM ...
 

Re:Re: std::string S; --> How S.sprintf ?

Ed Mulroy [TeamB] < XXXX@XXXXX.COM >wrote:
Quote
Side comment:

>The interesting part of the standardese is that c_str()
>may invalidate &s[0] (21.3/5), which is effectively stating
>that c_str() may cause a memory reallocation. This may
>be because the string has a contiguous ...

Or it could be that the STL designer, having been beaten up once too
often by marketing types over people who run into trouble when
misusing his products. then allocates a buffer different from that
which holds the instance' internal data, this buffer to be used
exclusively as the c_str() return value.
ed.txt, line #3: General parse error.
Is that me being German, or /is/ there really
something wrong with that/those sentence(s)?
Quote
. Ed
Schobi
--
XXXX@XXXXX.COM is never read
I'm Schobi at suespammers dot org
"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett
 

Re:Re: std::string S; --> How S.sprintf ?

Quote
Is that me being German, or /is/ there really
something wrong with that/those sentence(s)?
No and probably.
You already are a native-speaker in German, a non-trivial language,
and superior in American English as the bulk of the people with whom I
come in contact.
Look at the syntax used in some German statements. There often are
several ways to express a thought. Different ways have slightly
altered means (as stated, cynicism, sarcasm, disbelief, emphasis,
etc). My item that you cited was a similar situation.
What you encountered was a combination of two things: an alternate way
of expressing something combined with (according to my high school
teacher, a most evil thing) a run-on sentence. It also was written
quickly so reflected no attempt at clarity.
Restating in a way that I hope will be better understood:
An STL designer might do that if he received complaints from marketing
types because of customer complaints to them. Although the complaints
in this case are most likely from invalid use he might still do
something to avoid them.
What he might do is to allocate a buffer when c_str() is called, one
into which a copy of the string contents is placed and return its
address. When the customer casts away the const on the c_str() return
value and modifies it, the underlying contents of the string remain
unaltered.
. Ed
Quote
Hendrik Schober wrote in message
news: XXXX@XXXXX.COM ...

>>The interesting part of the standardese is that c_str()
>>may invalidate &s[0] (21.3/5), which is effectively stating
>>that c_str() may cause a memory reallocation. This may
>>be because the string has a contiguous ...
>
>Or it could be that the STL designer, having been beaten up once
>too
>often by marketing types over people who run into trouble when
>misusing his products. then allocates a buffer different from that
>which holds the instance' internal data, this buffer to be used
>exclusively as the c_str() return value.

ed.txt, line #3: General parse error.

Is that me being German, or /is/ there really
something wrong with that/those sentence(s)?

>. Ed

Schobi

--
XXXX@XXXXX.COM is never read
I'm Schobi at suespammers dot org

"The presence of those seeking the truth is infinitely
to be prefered to those thinking they've found it."
Terry Pratchett


 

Re:Re: std::string S; --> How S.sprintf ?

Ed Mulroy [TeamB] wrote:
Quote
What he might do is to allocate a buffer when c_str() is called, one
into which a copy of the string contents is placed and return its
address. When the customer casts away the const on the c_str()
return value and modifies it, the underlying contents of the string
remain unaltered.
But he has broken another invariant:
If the string is named s:
The range [s.begin(), s.end ) will contain different values to the range
[s.c_str(), s.c_str() + size() )
Which is the correct version of the string?
Which buffer do the different member functions use?
Plus you just double the memory consumption for every string var, to
protect against deliberate misuse in a handful of corner cases. I
think that would bring far more customer complaints than the one your
mythical vendor is trying to address <g>
AlisdairM(TeamB)
 

Re:Re: std::string S; --> How S.sprintf ?

"Alisdair Meredith" <alisdair.meredith@ XXXX@XXXXX.COM >writes:
Quote
The range [s.begin(), s.end ) will contain different values to the range
[s.c_str(), s.c_str() + size() )
[And now for something completely different.]
Is the second range really guaranteed to be a range?
I.e. is s.c_str() + size() guaranteed to be reachable from s.c_str()?
Could an implementation return two unrelated pointers from two calls
to s.c_str()?
 

Re:Re: std::string S; --> How S.sprintf ?

Thomas Maeder [TeamB] wrote:
Quote
[And now for something completely different.]

Is the second range really guaranteed to be a range?

I.e. is s.c_str() + size() guaranteed to be reachable from s.c_str()?
Could an implementation return two unrelated pointers from two calls
to s.c_str()?
You were not supposed to ask that question <g>
To be honest I am not 100% clear on how long the pointer returned by
c_str() *must* remain valid. My research on the topic has not been
very re-assuring - I have not found anything to guarantee the buffer
exists beyond the call to c_str() itself. That would be pretty useless
if adhered to strictly - you could not even safely pass it to legacy
'C' functions, the main reason it exists! The fact of the matter is
that is does what is expected on all implementations I have used
(return the internal buffer, and be valid until something else
invalidates said buffer) and I do not rule out there being wording that
guarantees this - I have simply not looked hard enough to identify it
yet.
AlisdairM(TeamB)