Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Microsoft dropped the ball...

251 views
Skip to first unread message

Mr Flibble

unread,
Sep 16, 2020, 3:17:03 PM9/16/20
to
Just submitted a VS2019 bug report (C++17 non-conformance):

std::cout << a() << "," << b(); // a() is not sequenced before b()

/Flibble

--
¬

Rick C. Hodgin

unread,
Sep 16, 2020, 3:34:37 PM9/16/20
to
On 9/16/20 3:16 PM, Mr Flibble wrote:
> Just submitted a VS2019 bug report (C++17 non-conformance):
>
> std::cout << a() << "," << b(); // a() is not sequenced before b()

Switch to C and that whole problem goes away, along with a few hundred
thousand?? others.

Write In C (Let It Be parody)
https://www.youtube.com/watch?v=1S1fISh-pag

C code may be a little more lengthy to accomplish the same task, but
given C++'s syntax, it's actually easier to read, faster to write,
and it makes you happy at the end of the day.

Just saying.

--
Rick C. Hodgin

Mr Flibble

unread,
Sep 16, 2020, 3:36:56 PM9/16/20
to
And Satan invented the fossil record, yes spammer?

--
¬

Rick C. Hodgin

unread,
Sep 16, 2020, 3:47:47 PM9/16/20
to
On 9/16/20 3:36 PM, Mr Flibble wrote:
> And Satan invented the fossil record, yes spammer?

No, purposefully ignorant person.

--
Rick C. Hodgin

Mr Flibble

unread,
Sep 16, 2020, 3:50:13 PM9/16/20
to
On 16/09/2020 20:16, Mr Flibble wrote:
> Just submitted a VS2019 bug report (C++17 non-conformance):
>
> std::cout << a() << "," << b(); // a() is not sequenced before b()

Report is: https://developercommunity.visualstudio.com/content/problem/1187555/vs2019-c-is-not-c17-confornment-operator-argument.html

/Flibble

--
¬

David Brown

unread,
Sep 16, 2020, 3:51:54 PM9/16/20
to
On 16/09/2020 21:34, Rick C. Hodgin wrote:
> On 9/16/20 3:16 PM, Mr Flibble wrote:
>> Just submitted a VS2019 bug report (C++17 non-conformance):
>>
>> std::cout << a() << "," << b(); // a() is not sequenced before b()
>
> Switch to C and that whole problem goes away, along with a few hundred
> thousand?? others.
>

C does not require "a()" to be evaluated before "b()" in an expression,
unless there are sequence points (like a comma) to force it. C++ was
the same until C++17, when "left to right" evaluation order was added
specifically because it is what people expect in an expression like
this. (Personally, I'm not sure that was the right solution - perhaps
making << and >> act as sequence points would have been better. But I
suppose the committee thought about that before making the change.)

Mr. Flibble is right - if MSVC is evaluating b() before a() in C++17
mode, it's a bug. In C++ before C++17, or in C, the order is unspecified.


Ben Bacarisse

unread,
Sep 16, 2020, 3:56:59 PM9/16/20
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:

> On 9/16/20 3:16 PM, Mr Flibble wrote:
>> Just submitted a VS2019 bug report (C++17 non-conformance):
>>
>> std::cout << a() << "," << b(); // a() is not sequenced before b()
>
> Switch to C and that whole problem goes away,

How so? C has weaker rules about expression evaluation sequencing than
C++ does and none that fix this issue with sequencing IO operations.

--
Ben.

Rick C. Hodgin

unread,
Sep 16, 2020, 3:58:11 PM9/16/20
to
You wouldn't write IO in that way in C, so the problem goes away.

--
Rick C. Hodgin

Ben Bacarisse

unread,
Sep 16, 2020, 4:17:15 PM9/16/20
to
David Brown <david...@hesbynett.no> writes:

> On 16/09/2020 21:34, Rick C. Hodgin wrote:
>> On 9/16/20 3:16 PM, Mr Flibble wrote:
>>> Just submitted a VS2019 bug report (C++17 non-conformance):
>>>
>>> std::cout << a() << "," << b(); // a() is not sequenced before b()
>>
>> Switch to C and that whole problem goes away, along with a few hundred
>> thousand?? others.
>
> C does not require "a()" to be evaluated before "b()" in an expression,
> unless there are sequence points (like a comma) to force it. C++ was
> the same until C++17, when "left to right" evaluation order was added
> specifically because it is what people expect in an expression like
> this.

I could not find where that is specified (but I have only a draft).

> (Personally, I'm not sure that was the right solution - perhaps
> making << and >> act as sequence points would have been better. But I
> suppose the committee thought about that before making the change.)

In N4713 both E1 << E2 and E1 >> E2 have explicit statements that E1 is
sequenced before E2 (much like the text for &&, || and the comma
operator as you suggest) but I could find not the general rule you refer
to further up.

> Mr. Flibble is right - if MSVC is evaluating b() before a() in C++17
> mode, it's a bug. In C++ before C++17, or in C, the order is
> unspecified.

I get confused by the drafts, but N3797, which I thought was a draft of
C++14, has the same explicit wording for << and >>. Maybe N3797 was a
very early draft of C++17.

--
Ben.

Mr Flibble

unread,
Sep 16, 2020, 4:33:14 PM9/16/20
to
The problem was operator error: it helps if you change the compiler settings for the build configuration you are actually building.

Sorry for the noise.

/Flibble

--
¬

Ben Bacarisse

unread,
Sep 16, 2020, 4:47:34 PM9/16/20
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:

> On 9/16/20 3:56 PM, Ben Bacarisse wrote:
>> "Rick C. Hodgin" <rick.c...@gmail.com> writes:
>>> On 9/16/20 3:16 PM, Mr Flibble wrote:
>>>> std::cout << a() << "," << b(); // a() is not sequenced before b()
>>>
>>> Switch to C and that whole problem goes away,
>>
>> How so? C has weaker rules about expression evaluation sequencing than
>> C++ does and none that fix this issue with sequencing IO operations.
>
> You wouldn't write IO in that way in C, so the problem goes away.

You can write it so that the problem goes away in C++ too, so what was
your point about switching C?

--
Ben.

David Brown

unread,
Sep 16, 2020, 4:51:52 PM9/16/20
to
I like it when you challenge me this way - it forces me to go back and
look for the details, and sometimes, like here, makes me realise I've
got things wrong.

I think I have been generalising from some "list of new features in
C++17", rather than looking a the real details. C++17 has actually done
pretty much what I said I'd prefer, rather than what I thought it had!

Some expression - E1[E2], E1.*E2, E1->*E2, E1 << E2, E1 >> E2, E2 = E1,
and E2 @= E1 (compound assignments) now have E1 sequences before E2 for
evaluation and side effects.

<https://en.cppreference.com/w/cpp/language/eval_order>

provides a summary that is easier to follow than the standards.

MSVC is still wrong, since C++17 forces the evaluation order of <<
expressions.

David Brown

unread,
Sep 16, 2020, 4:53:25 PM9/16/20
to
The thread made me think, let me make a mistake, let my mistake get
spotted, let me correct my mistake and learn a little more accurate
details. So I am glad for the noise here!


Mr Flibble

unread,
Sep 16, 2020, 4:54:17 PM9/16/20
to
MSVC is only wrong if you choose language standard compiler setting of pre-C++17. Yes it was operator error. :/

/Flibble

--
¬

Juha Nieminen

unread,
Sep 16, 2020, 5:44:09 PM9/16/20
to
Oh, so nobody ever writes things like

printf("%i,%i", a(), b())

in C?

Right...

Rick C. Hodgin

unread,
Sep 16, 2020, 5:44:36 PM9/16/20
to
On 9/16/20 4:47 PM, Ben Bacarisse wrote:
> "Rick C. Hodgin" <rick.c...@gmail.com> writes:
>> You wouldn't write IO in that way in C, so the problem goes away.
>
> You can write it so that the problem goes away in C++ too, so what was
> your point about switching C?

100% humor.

--
Rick C. Hodgin

Rick C. Hodgin

unread,
Sep 16, 2020, 6:05:28 PM9/16/20
to
On 9/16/20 5:43 PM, Juha Nieminen wrote:
> Rick C. Hodgin <rick.c...@gmail.com> wrote:
>> You wouldn't write IO in that way in C, so the problem goes away.
> Oh, so nobody ever writes things like
> printf("%i,%i", a(), b())
> in C?

You tell me. Per the bug report he submitted to Visual Studio 2019:

int a(void)
{
return 1;
}

int b(void)
{
return 2;
}

int main(int argc, char* argv[])
{
// C++ way
std::cout << a() << b();
std::cout << std::endl;
// Reports 12

// C++ way
std::cout << (a() << b());
std::cout << std::endl;
// Reports 4

// C way
printf("%d\n", a() << b());
// Reports 4

return 0;
}

I only have Visual Studio 2003 on this computer, and it reports 12, 4,
and 4. It should be reporting 4, 4, and 4, in C++17.

C gets it right. C++ does too with a little help from its friends
(parenthetically speaking of course).

> Right...

See how easy it is to misunderstand something? You do it effortlessly.
You make it look easy. :-)

Actually, this would be a great teaching moment for Bonita. It
demonstrates that adding an extra set of parenthesis now and then
removes real-world code issues.

--
Rick C. Hodgin

Ben Bacarisse

unread,
Sep 16, 2020, 7:07:10 PM9/16/20
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:

> On 9/16/20 4:47 PM, Ben Bacarisse wrote:
>> "Rick C. Hodgin" <rick.c...@gmail.com> writes:
>>> You wouldn't write IO in that way in C, so the problem goes away.
>>
>> You can write it so that the problem goes away in C++ too, so what was
>> your point about switching C?
>
> 100% humor.

It seems, from another post, that you did not understand the issue.
Hmm... or maybe that post was intended to be funny too. You might
consider marking, in some way, those posts that you'd like to be taken
seriously.

--
Ben.

Ben Bacarisse

unread,
Sep 16, 2020, 7:34:24 PM9/16/20
to
"Rick C. Hodgin" <rick.c...@gmail.com> writes:

> On 9/16/20 5:43 PM, Juha Nieminen wrote:
>> Rick C. Hodgin <rick.c...@gmail.com> wrote:
>>> You wouldn't write IO in that way in C, so the problem goes away.
>> Oh, so nobody ever writes things like
>> printf("%i,%i", a(), b())
>> in C?
>
> You tell me. Per the bug report he submitted to Visual Studio 2019:
>
> int a(void)
> {
> return 1;
> }
>
> int b(void)
> {
> return 2;
> }

This is not "per the bug report". You picked these, possibly unaware
that they are useless examples. The bug report and no explicit a and b.

> int main(int argc, char* argv[])
> {
> // C++ way
> std::cout << a() << b();
> std::cout << std::endl;
> // Reports 12

As it must. Your a() and b() can't illustrate the problem, because it's
about side effects.

> // C++ way
> std::cout << (a() << b());
> std::cout << std::endl;
> // Reports 4

The issue is about operator precedence and parentheses.

> // C way
> printf("%d\n", a() << b());

The C equivalent of the original posted code is (depending on the return
type)

printf("%d,%d\n", a(), b());

and suitable examples to show a potential sequencing bug might be

int a(void) { fprintf(stderr, "a called\n"); return 1; }
int b(void) { fprintf(stderr, "b called\n"); return 2; }

(writing (void) because these are being used in C and C++ code).

Prior to C++17,

std::cout << a() << "," << b() << "\n";

could produce either

a called
b called

or

b called
a called

on stderr, though always

1,2

on stdout. C++17 added a rule that in E1 << E2, E1 is sequenced before
E2. That is a statement about when any side effects must be seen to occur,
and is not about operator precedence.

In C, the "problem" (if one chooses to see it as one), persists to this
day. All function argument evaluations are sequenced before the call,
but are unsequenced with respect to each other. In this case, a and b
must both be called and any side effects completed before the call to
printf, but a and b can be called in either order.

> // Reports 4
>
> return 0;
> }
>
> I only have Visual Studio 2003 on this computer, and it reports 12, 4,
> and 4. It should be reporting 4, 4, and 4, in C++17.

Your example a() and b() can't show the issue.

> C gets it right. C++ does too with a little help from its friends
> (parenthetically speaking of course).

It's not about parentheses.

>> Right...
>
> See how easy it is to misunderstand something? You do it
> effortlessly. You make it look easy. :-)

And here's a smilie. So was the above just all a big joke too? No
matter; maybe someone else will get something from reading it.

> Actually, this would be a great teaching moment for Bonita. It
> demonstrates that adding an extra set of parenthesis now and then
> removes real-world code issues.

Parentheses can't help.

--
Ben.

Rick C. Hodgin

unread,
Sep 16, 2020, 8:08:42 PM9/16/20
to
On 9/16/20 7:34 PM, Ben Bacarisse wrote:
> ...C++17 added a rule that in E1 << E2, E1 is sequenced before E2.

Yeah. My mistake. I misunderstood.

I thought the issue to be the overloaded << operator working on the
result of a() shift left b(), compared to outputting a() and b() as
values to stdout.

If I understand the issue correctly now, that e1 is called before
e2 ??, then I think that's only natural. I would find the fact that
it didn't work that way before to be surprising.

And if I still misunderstand then I really don't care. The length
of this conversation is already way out of proportion to my level
of interest in it.

--
Rick C. Hodgin

Chris M. Thomasson

unread,
Sep 17, 2020, 2:07:54 AM9/17/20
to
On 9/16/2020 12:16 PM, Mr Flibble wrote:
> Just submitted a VS2019 bug report (C++17 non-conformance):
>
> std::cout << a() << "," << b(); // a() is not sequenced before b()

Really? I have 2017 installed. Its just that I never use function calls
in cout sequences.

Chris M. Thomasson

unread,
Sep 17, 2020, 2:10:48 AM9/17/20
to
Have to admit that I prefer printf over cout in a lot of cases.

Juha Nieminen

unread,
Sep 17, 2020, 3:05:31 AM9/17/20
to
Rick C. Hodgin <rick.c...@gmail.com> wrote:
> On 9/16/20 7:34 PM, Ben Bacarisse wrote:
>> ...C++17 added a rule that in E1 << E2, E1 is sequenced before E2.
>
> If I understand the issue correctly now, that e1 is called before
> e2 ??, then I think that's only natural. I would find the fact that
> it didn't work that way before to be surprising.

Actually it's not really "natural" because it's a very widely known fact
(and warning) that if you do something like:

someFunction(a(), b(), c());

the order in which those functions a(), b() and c() are called is not
guaranteed. The compiler is free to call them in any order it wants
(and, indeed, different compilers *do* call them in different orders
in practice. It's not just theoretical.)

Likewise if you do something like this:

x = a() + b() + c();

the order in which of those function calls are done is not guaranteed.
Once again the compiler is free to do them in whatever order it wants.

Because of this, it's not so obvious why in

std::cout << a() << b() << c();

those functions couldn't likewise be called in whatever order the
compiler wants (as long as the operator<<() function calls are done
in the specified order, which is independent of the order in which
the function calls a(), b() and c() are done.)

I suppose C++17 decided to make an exception in this case, and
mandated that with such operators as << the order in which the
parameters are evaluated should be fixed.

Juha Nieminen

unread,
Sep 17, 2020, 3:11:53 AM9/17/20
to
Chris M. Thomasson <chris.m.t...@gmail.com> wrote:
> Have to admit that I prefer printf over cout in a lot of cases.

There are other cases where std::cout is just more practical.

Suppose, for example, that you wanted to implement a simpler printing
function, for example just to print some debugging messages, that you
can call like:

int a = 5;
MyCustomClass b;
std::string str = "hello";

dPrint("The value of a is ", a, ", that of b is ", b,
", and str is \", str, "\"\n");

Implementing such a function is perfectly possible, even easy. But
it's easy only if you use std::cout in its implementation. Not so easy
if you wanted to use std::printf instead.

Öö Tiib

unread,
Sep 17, 2020, 3:15:19 AM9/17/20
to
Both are good enough for command line human I/O but for something
more demanding ... neither is efficient nor convenient enough.
Both have some kind of laughably insufficient and cryptic i18n
support in those that totally degrades the performance. That
cout even makes virtual calls! :D

Consider: we receive compile time warnings about printf format
specifiers from several compilers. Yet those compile it into
program that parses that format string run time again. Why?
Because of that sub-par localisation garbage that does nothing
else but causes confusion sometimes. The gettext library for
example totally rewrites it to achieve something useful for i18n.

David Brown

unread,
Sep 17, 2020, 3:21:24 AM9/17/20
to
Given that the sequencing was unspecified until C++17, then it is a good
idea to avoid << chains that rely on the sequencing. The change was
made in C++17 because some people /did/ write code that had << chains
with function calls, believing that the order of evaluation (and
side-effects) was guaranteed.

Öö Tiib

unread,
Sep 17, 2020, 3:42:01 AM9/17/20
to
Some languages have solution to that problem as part of string class.
For example Swift:

var text = "The value of a is \(a) that of b is \(b) and str is \"\(str)\"\n"

Swift is compiling to LLVM and performs similarly to C and C++.

Bo Persson

unread,
Sep 17, 2020, 4:27:01 AM9/17/20
to
Function calls are fine, unless calling one function affects the result
of the other function. Having such a combo is a bit unstable, not only
for I/O.

Juha Nieminen

unread,
Sep 17, 2020, 7:34:38 AM9/17/20
to
Öö Tiib <oot...@hot.ee> wrote:
> Consider: we receive compile time warnings about printf format
> specifiers from several compilers. Yet those compile it into
> program that parses that format string run time again. Why?
> Because of that sub-par localisation garbage that does nothing
> else but causes confusion sometimes. The gettext library for
> example totally rewrites it to achieve something useful for i18n.

I don't really understand why the C++ standard library (and possibly the
C standard library, where C++ "inherited" it) decided to go with those
stupid localization complications.

It has bitten me in the posterior in the form of the precise format that
std::atof() accepts depending on the locale (more precisely, the exact
character used as the decimal point depends on the locale), which made
it completely useless for my purposes (because I wanted to parse
floating point values in a fixed format).

No wonder they added the from_chars() functions to address this problem.

Leo

unread,
Sep 17, 2020, 11:12:24 AM9/17/20
to
On 9/17/20 10:41 AM, Öö Tiib wrote:
> Swift is compiling to LLVM and performs similarly to C and C++.

In what world is Swift performing similarly to C and C++? Maybe badly
written C or Swift that no longer looks like Swift.

For 99% of the code mortals will come across, Swift performs much much
worse than C or C++.

daniel...@gmail.com

unread,
Sep 17, 2020, 11:26:41 AM9/17/20
to
On Thursday, September 17, 2020 at 7:34:38 AM UTC-4, Juha Nieminen wrote:
> I don't really understand why the C++ standard library (and possibly the
> C standard library, where C++ "inherited" it) decided to go with those
> stupid localization complications.
>
Agreed. Localization is about formatting, basic conversion should be into
canonical forms.

C++ streams have an imbue modifier, that allows you to set the locale to
the "C" (minimal) locale. But libraries that have to compete with others
can't use streams for text/numeric conversion because that would be too slow
compared to their competitors. So they use the _l (locale independent) C functions
where they exist, and where they don't, they jump through hoops to reverse the
affects of localization from sprintf, sscanf and strtod. Serialization libraries that
make claims about speed generally avoid the C++ streams and the C
functions altogether, and provide their own implementations of number to text and
text to number, usually with inexact float parsing.

>
> No wonder they added the from_chars() functions to address this problem.

Regarding characters, C++ has char, signed char, unsigned char, char8_t,
char16_t, char32_t, and wchar. And C++ has the notion of generics. So I don't understand
why a function named from_chars is limited to taking a sequence of char. Or why
a function named to_chars is limited to writing into a range of char.

Daniel

Öö Tiib

unread,
Sep 17, 2020, 12:17:12 PM9/17/20
to
Cite?

Melzzzzz

unread,
Sep 17, 2020, 1:02:18 PM9/17/20
to
If functions don't have side effect, then no problem. In haskell almost
evry function is pure, that is you can't predict when they are evaluated
;)


--
current job title: senior software engineer
skills: c++,c,rust,go,nim,haskell...

press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala

Leo

unread,
Sep 17, 2020, 1:06:06 PM9/17/20
to
How can I prove that Swift performs similarly to C, I don't even know
Swift. You need to write benchmarks so C/C++/Rust developers can fix the
performance bugs that make them as slow as Swift.

Juha Nieminen

unread,
Sep 17, 2020, 2:29:27 PM9/17/20
to
Leo <use...@gkbrk.com> wrote:
> On 9/17/20 7:16 PM, ?? Tiib wrote:
>> On Thursday, 17 September 2020 18:12:24 UTC+3, Leo wrote:
>>> On 9/17/20 10:41 AM, ?? Tiib wrote:
>>>> Swift is compiling to LLVM and performs similarly to C and C++.
>>>
>>> In what world is Swift performing similarly to C and C++? Maybe badly
>>> written C or Swift that no longer looks like Swift.
>>>
>>> For 99% of the code mortals will come across, Swift performs much much
>>> worse than C or C++.
>>
>> Cite?
>
> How can I prove that Swift performs similarly to C, I don't even know
> Swift.

You don't know Swift, but you know it performs much worse?

Based on what?

Öö Tiib

unread,
Sep 17, 2020, 2:46:07 PM9/17/20
to
On Thursday, 17 September 2020 18:26:41 UTC+3, daniel...@gmail.com wrote:
>
> Regarding characters, C++ has char, signed char, unsigned char, char8_t,
> char16_t, char32_t, and wchar. And C++ has the notion of generics.

Some are historically there but newer ones seem to be added to
make things more confused. All of those besides char are anyway
less useful than char and nothing helps it.

> So I don't understand why a function named from_chars is limited
> to taking a sequence of char. Or why a function named to_chars is
> limited to writing into a range of char.

Best performant storage types for manipulating texts are std::string,
std::vector<char>, std::array<char,N> and raw char array. Also
std::string_view is useful as it can refer to contents of any of
those types.

It is like most useful encoding is BOMless UTF-8 encoding (or
its proper subset ASCII) that also works great in those
containers. Everything else is just kook stuff, family
of EBCDIC.

Therefore performance features from_chars and to_chars are
doing the obvious ... namely reading and writing chars in most
performant containers of text. The only thing left dim there is
about INF and NAN otherwise those are all what is needed.

Keith Thompson

unread,
Sep 17, 2020, 3:21:11 PM9/17/20
to
Öö Tiib <oot...@hot.ee> writes:
> On Thursday, 17 September 2020 18:26:41 UTC+3, daniel...@gmail.com wrote:
>>
>> Regarding characters, C++ has char, signed char, unsigned char, char8_t,
>> char16_t, char32_t, and wchar. And C++ has the notion of generics.

wchar_t, not wchar.

> Some are historically there but newer ones seem to be added to
> make things more confused. All of those besides char are anyway
> less useful than char and nothing helps it.

unsigned char is very useful for accessing raw memory.

wchar_t is vital for dealing with wide character data on Windows.
(I *wish* Windows used UTF-8 rather than UTF-16, but it doesn't.)

[...]

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Ben Bacarisse

unread,
Sep 17, 2020, 4:02:00 PM9/17/20
to
Melzzzzz <Melz...@zzzzz.com> writes:

> On 2020-09-17, Chris M. Thomasson <chris.m.t...@gmail.com> wrote:
>> On 9/16/2020 12:16 PM, Mr Flibble wrote:
>>> Just submitted a VS2019 bug report (C++17 non-conformance):
>>>
>>> std::cout << a() << "," << b(); // a() is not sequenced before b()
>>
>> Really? I have 2017 installed. Its just that I never use function calls
>> in cout sequences.
>
> If functions don't have side effect, then no problem. In haskell almost
> evry function is pure, that is you can't predict when they are evaluated
> ;)

But, but, but! Haskell is a lazy language, and guaranteed to be so, so
you can often predict when a function /won't/ be evaluated! For
example, there must be no IO resulting from this definition

x = [putStrLn "a", putStrLn "b"]

A more extreme example would be

y = last [1..]

which defines y to be the "last" positive integer. No problem. You can
define many other things using z. What you can't do is inspect any of
them.

--
Ben.

Öö Tiib

unread,
Sep 17, 2020, 4:04:11 PM9/17/20
to
On Thursday, 17 September 2020 22:21:11 UTC+3, Keith Thompson wrote:
> Öö Tiib <oot...@hot.ee> writes:
> > On Thursday, 17 September 2020 18:26:41 UTC+3, daniel...@gmail.com wrote:
> >>
> >> Regarding characters, C++ has char, signed char, unsigned char, char8_t,
> >> char16_t, char32_t, and wchar. And C++ has the notion of generics.
>
> wchar_t, not wchar.
>
> > Some are historically there but newer ones seem to be added to
> > make things more confused. All of those besides char are anyway
> > less useful than char and nothing helps it.
>
> unsigned char is very useful for accessing raw memory.

Yes, I meant for text. For raw bits/bytes I actually prefer to use
it under name uint8_t as it is shorter to write, has single word
identifier and ensures that either the resulting bytes are platform
agnostic or the code does not compile.

> wchar_t is vital for dealing with wide character data on Windows.
> (I *wish* Windows used UTF-8 rather than UTF-16, but it doesn't.)

Yes, same with Qt. Translating between UTF-16LE and UTF-8 is
fortunately trivial in module interface. Yes, sad, I like
Windows somewhat. May be one day Mr Flibble's neoGFX saves us
from Qt. ;)

Jorgen Grahn

unread,
Sep 17, 2020, 4:10:44 PM9/17/20
to
On Thu, 2020-09-17, Juha Nieminen wrote:
> Öö Tiib <oot...@hot.ee> wrote:
>> Consider: we receive compile time warnings about printf format
>> specifiers from several compilers. Yet those compile it into
>> program that parses that format string run time again. Why?
>> Because of that sub-par localisation garbage that does nothing
>> else but causes confusion sometimes. The gettext library for
>> example totally rewrites it to achieve something useful for i18n.
>
> I don't really understand why the C++ standard library (and possibly the
> C standard library, where C++ "inherited" it) decided to go with those
> stupid localization complications.

Also, I've never (at home or at work) had any use for any of it.
Customers have never wanted a user interface not in English, and so
on.

Maybe it was an idea that sounded like a good idea in the 1980s.
Or maybe it /is/ a good idea in countries where people don't accept
English as the lingua franca in technology, e.g. France.

To be honest, there is one feature I want, too: I want sorting of
strings to take my national characters into account ("Öö" would sort
last). I can get that with LC_COLLATE="sv_SE". But then I get
things I probably /don't/ want too, such as case-insensitive sort.
It's a blunt instrument.

> It has bitten me in the posterior in the form of the precise format that
> std::atof() accepts depending on the locale (more precisely, the exact
> character used as the decimal point depends on the locale), which made
> it completely useless for my purposes (because I wanted to parse
> floating point values in a fixed format).

Here is another bluntness: sv_SE implements the old 12.345,67 syntax
for saying 12345.67, but people are just as likely to input 12345.67,
especially if they're programmers, or have any international contacts
at all[1]. So you can't always use it in a localized user interface,
either. Not without annoying people.

/Jorgen

[1] E.g. by being on the Internet.

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

daniel...@gmail.com

unread,
Sep 17, 2020, 4:34:45 PM9/17/20
to
On Thursday, September 17, 2020 at 2:46:07 PM UTC-4, Öö Tiib wrote:
> On Thursday, 17 September 2020 18:26:41 UTC+3, daniel...@gmail.com wrote:
> >
> > Regarding characters, C++ has char, signed char, unsigned char, char8_t,
> > char16_t, char32_t, and wchar. And C++ has the notion of generics.
> Some are historically there but newer ones seem to be added to
> make things more confused. All of those besides char are anyway
> less useful than char and nothing helps it.
> > So I don't understand why a function named from_chars is limited
> > to taking a sequence of char. Or why a function named to_chars is
> > limited to writing into a range of char.

> Best performant storage types for manipulating texts are std::string,
> std::vector<char>, std::array<char,N> and raw char array. Also
> std::string_view is useful as it can refer to contents of any of
> those types.

> Therefore performance features from_chars and to_chars are
> doing the obvious ... namely reading and writing chars in most
> performant containers of text.

For those types, reading from an iterator pair and writing to an
output iterator would be no less performant, and provide
more flexibility. And support char8_t, char16_t and char32_t too.
Limiting to char* simply increases the likelihood
that a temporary buffer will be needed, requiring copying
from the source or to the destination. With iterators,
they couldn't have made the same guarantee of
non-throwing, but the caller can make that decision.
>
Daniel

Öö Tiib

unread,
Sep 17, 2020, 5:50:07 PM9/17/20
to
How you implement it in generic manner? Reverse engineer back
to type and then have lookup tables for each of 'a', u8'a',
L'a', u'a' and U'a' to compare with 'a' when base is 11?


daniel...@gmail.com

unread,
Sep 17, 2020, 6:18:59 PM9/17/20
to
I don't understand your point. The characters that from_chars
and to_chars support, 0-9, a..z (for the integer conversions in
different bases), '.', a..f (hex floating point), '-', 'e', have the same
numerical values in ansii, UTF-8, UTF-16, and UTF-32. There is
no need to look up anything.

Daniel

Ian Collins

unread,
Sep 17, 2020, 7:00:55 PM9/17/20
to
That is how I have updated our project logging; from a user's
perspective, the log print is the same as python3 print :)

--
Ian.

olcott

unread,
Sep 17, 2020, 9:07:17 PM9/17/20
to
It didn't occur to me until my other recent post that my use of printf
over cout is not merely laziness, printf is simply better at formatted
output.

--
Copyright 2020 Pete Olcott

Chris M. Thomasson

unread,
Sep 17, 2020, 11:56:55 PM9/17/20
to
Actually, using printf can sometimes be more "difficult" to use.
However, I still try to employ it when I can.

Juha Nieminen

unread,
Sep 18, 2020, 2:35:58 AM9/18/20
to
daniel...@gmail.com <daniel...@gmail.com> wrote:
> For those types, reading from an iterator pair and writing to an
> output iterator would be no less performant, and provide
> more flexibility.

The iterator idiom is certainly very flexible and adds a lot of possibilities
that a "hard-coded" (so-to-speak) non-iterator based solution like
from_chars() and to_chars() can't offer.

For example, if the output would be specified with an iterator, you could
use something like a back_insert_iterator, or a ostream_iterator, or
whatever you want. Likewise for input, iterators wouldn't force you to have
the input string being in an actual array, but be eg. generated on the fly.

That being said, there could potentially be some efficiency benefits in
taking char*'s directly, rather than iterators: It opens the possibility
for the implementation to do things more efficiently than forward iterators
would allow, such as traversing the string backwards, or random-accessing
it. (You could make the iterator-based version require random access
iterators, but that would immediately cut off a lot of the benefits of
the iterator-based solution in the first place.)

> And support char8_t, char16_t and char32_t too.

I suppose the functions could be overloaded with versions taking those
types of pointers...

Juha Nieminen

unread,
Sep 18, 2020, 2:44:04 AM9/18/20
to
olcott <No...@nowhere.com> wrote:
> It didn't occur to me until my other recent post that my use of printf
> over cout is not merely laziness, printf is simply better at formatted
> output.

Its major problem (besides not being type-safe) is that it's not extensible
with custom types and formatting.

Sure, you could write things like:

std::printf("a=%i, b=", a);
printMyCustomType(b);
std::printf(", c=%f\n", c);

but that's not very practical in all situations.

It's also not very generic:

template<typename T>
void debugPrint(const T& value)
{
std::printf("... uh ...", value); // ???
}

You could add overloads for every type supported by printf, but with
std::ostream you don't have to because it already defines those
overloads:

template<typename T>
void debugPrint(const T& value)
{
std::cout << value;
}

Also, a printf-based version would be more awkward when it comes to defining
formatting parameters. With a generic ostream-based version nothing stops you
from using its own formatting elements, like:

debugPrint("a=", std::hex, a);

(You can even implement that debugPrint() function in such a manner that it
restores the formatting flags of std::cout before it returns, so any
formatting changes don't linger afterwards.)

Bonita Montero

unread,
Sep 18, 2020, 6:53:06 AM9/18/20
to
> The problem was operator error: it helps if you change the compiler
> settings for the build configuration you are actually building.

Aside the compiler is actually right:
I think calling f2() and then f1() before cout without -std:c++ is
because the return of f2 is pushed first on the stack and then f1,
which fits to the topmost position which is required for the first
cout::operator << call.

Bonita Montero

unread,
Sep 18, 2020, 7:40:00 AM9/18/20
to
> Aside the compiler is actually right:
> I think calling f2() and then f1() before cout without -std:c++ is
> because the return of f2 is pushed first on the stack and then f1,
> which fits to the topmost position which is required for the first
> cout::operator << call.

Sorry, I missed that operator << doesn't take a string-object.
There isn't even an overload that takes a string-reference. So
how does this work that you can output a string object to an
ostream ?

Bonita Montero

unread,
Sep 18, 2020, 7:45:08 AM9/18/20
to
I missed the global overloads.

Bo Persson

unread,
Sep 18, 2020, 7:50:24 AM9/18/20
to
There *is* an overload, but in the <string> header, not in the <ostream>
header.

https://en.cppreference.com/w/cpp/string/basic_string/operator_ltltgtgt



Bo Persson

Paavo Helde

unread,
Sep 18, 2020, 8:42:42 AM9/18/20
to
18.09.2020 09:43 Juha Nieminen kirjutas:
> olcott <No...@nowhere.com> wrote:
>> It didn't occur to me until my other recent post that my use of printf
>> over cout is not merely laziness, printf is simply better at formatted
>> output.
>
> Its major problem (besides not being type-safe) is that it's not extensible
> with custom types and formatting.
>
> Sure, you could write things like:
>
> std::printf("a=%i, b=", a);
> printMyCustomType(b);
> std::printf(", c=%f\n", c);

Sure it is extensible. The custom types must just be capable to produce
a string representation of themselves:

std::printf("a=%i, b=%s, c=%f", a, b.ToString().c_str(), c);

Considering that file output is slow anyway, constructing a
"superfluous" temporary string does not even affect performance.
Formatting parameters can be easily passed as arguments to ToString().

The only problem with std::printf() is the lack of type safety, but one
can create typesafe equivalents in C++, retaining the general printf
interface. There are many such solutions. I like my personal one which
overloads operator().

Alf P. Steinbach

unread,
Sep 18, 2020, 8:48:12 AM9/18/20
to
On 17.09.2020 09:11, Juha Nieminen wrote:
> Chris M. Thomasson <chris.m.t...@gmail.com> wrote:
>> Have to admit that I prefer printf over cout in a lot of cases.
>
> There are other cases where std::cout is just more practical.
>
> Suppose, for example, that you wanted to implement a simpler printing
> function, for example just to print some debugging messages, that you
> can call like:
>
> int a = 5;
> MyCustomClass b;
> std::string str = "hello";
>
> dPrint("The value of a is ", a, ", that of b is ", b,
> ", and str is \", str, "\"\n");
>
> Implementing such a function is perfectly possible, even easy. But
> it's easy only if you use std::cout in its implementation. Not so easy
> if you wanted to use std::printf instead.

I prefer a common solution for basic string composition, writing the
above as e.g.

d_print( ""s
<< "The value of a is " << a << ", that of b is " << b
<< ", and str is “" << str << "”.\n"
);

This way the function only needs a `const string_view&` parameter, or
the like, and the work of handling composition of umpteen args of
different types, does not have to be repeated in every such function.

I guess with the Fmt library in C++20 the specific syntax I use will
change, but same concept: centralize basic string composition,
centralize getter of filename and line number (well, that's almost
solved in C++20, all one needs is to leverage the standard library to
make an exception safe solution), and so on. Centralization, yay! Uh...

- Alf

Juha Nieminen

unread,
Sep 18, 2020, 9:56:50 AM9/18/20
to
Paavo Helde <ees...@osa.pri.ee> wrote:
>> Its major problem (besides not being type-safe) is that it's not extensible
>> with custom types and formatting.
>>
>> Sure, you could write things like:
>>
>> std::printf("a=%i, b=", a);
>> printMyCustomType(b);
>> std::printf(", c=%f\n", c);
>
> Sure it is extensible. The custom types must just be capable to produce
> a string representation of themselves:
>
> std::printf("a=%i, b=%s, c=%f", a, b.ToString().c_str(), c);

Extending std::ostream to support your custom type would usually not require
such temporary string buffers. Moreover, it grants you access to the
std::ostream object itself, giving you the option of *how* to output the
data (for example you could use std::ostream::write() instead of the regular
operator<<'s). With that scheme you propose you don't have access to the
FILE* where you are outputting, and thus you don't have, for example, the
option of using std::fwrite() if you so wanted.

Also, somewhat ironically, in some cases you would need to resort to
stringstreams in order to create the string to be printed.

> The only problem with std::printf() is the lack of type safety, but one
> can create typesafe equivalents in C++, retaining the general printf
> interface. There are many such solutions. I like my personal one which
> overloads operator().

Not the only problem. I mentioned the other one: printf() is not generic
enough. You can't use it when the type of the value to print is abstracted
away (eg. it's a template type parameter). At least not even nearly as
easily as with std::ostream.

Richard Damon

unread,
Sep 18, 2020, 10:20:38 AM9/18/20
to
On 9/17/20 9:06 PM, olcott wrote:
>
> It didn't occur to me until my other recent post that my use of printf
> over cout is not merely laziness, printf is simply better at formatted
> output.

printf can be easier for fundamental types (of known type). It is very
hard to use for 'class' objects, particularly for polymorphic types. It
does give more concise formatting the fundamental types.

iostreams can be easier in generic code, as << will 'do the right thing'
for the type. Since it lets the type decide how to output itself, it
does make it harder to control the output at the point of use.

Melzzzzz

unread,
Sep 18, 2020, 11:16:34 AM9/18/20
to
Isn't it that printf can be now implemented in type safe manner?

Paavo Helde

unread,
Sep 18, 2020, 11:30:06 AM9/18/20
to
18.09.2020 16:56 Juha Nieminen kirjutas:
> Paavo Helde <ees...@osa.pri.ee> wrote:
>>> Its major problem (besides not being type-safe) is that it's not extensible
>>> with custom types and formatting.
>>>
>>> Sure, you could write things like:
>>>
>>> std::printf("a=%i, b=", a);
>>> printMyCustomType(b);
>>> std::printf(", c=%f\n", c);
>>
>> Sure it is extensible. The custom types must just be capable to produce
>> a string representation of themselves:
>>
>> std::printf("a=%i, b=%s, c=%f", a, b.ToString().c_str(), c);
>
> Extending std::ostream to support your custom type would usually not require
> such temporary string buffers. Moreover, it grants you access to the
> std::ostream object itself, giving you the option of *how* to output the
> data (for example you could use std::ostream::write() instead of the regular
> operator<<'s). With that scheme you propose you don't have access to the
> FILE* where you are outputting, and thus you don't have, for example, the
> option of using std::fwrite() if you so wanted.

I thought we were talking about formatted output, that's what fprintf()
and streams are all about. I'm curious, how many times have you used
std::ostream::write() in your operator<< ?

Also, I consider it a good thing to modularize the program. Why should
the code formatting the object content know or care about streams or
FILE* pointers? Moreover, this way my output may easily become broken if
the stream or FILE happens to use a strange locale.

> Also, somewhat ironically, in some cases you would need to resort to
> stringstreams in order to create the string to be printed.

So what? This is an implementation detail.

>
>> The only problem with std::printf() is the lack of type safety, but one
>> can create typesafe equivalents in C++, retaining the general printf
>> interface. There are many such solutions. I like my personal one which
>> overloads operator().
>
> Not the only problem. I mentioned the other one: printf() is not generic
> enough. You can't use it when the type of the value to print is abstracted
> away (eg. it's a template type parameter). At least not even nearly as
> easily as with std::ostream.

How comes? If everything supports conversion to strings, it's trivial to
use in templates. Since C++11 we also have std::to_string() for
primitive types, so they could be easily incorporated as well if needed.

I mean, using C++ streams for formatted output is fine, I do not intend
to attack it in any way. I just objected the claim "printf-like
interface is not extensible with custom types and formatting".

Manfred

unread,
Sep 18, 2020, 11:39:37 AM9/18/20
to
On 9/17/2020 10:10 PM, Jorgen Grahn wrote:
> On Thu, 2020-09-17, Juha Nieminen wrote:
>> Öö Tiib <oot...@hot.ee> wrote:
>>> Consider: we receive compile time warnings about printf format
>>> specifiers from several compilers. Yet those compile it into
>>> program that parses that format string run time again. Why?
>>> Because of that sub-par localisation garbage that does nothing
>>> else but causes confusion sometimes. The gettext library for
>>> example totally rewrites it to achieve something useful for i18n.
>>
>> I don't really understand why the C++ standard library (and possibly the
>> C standard library, where C++ "inherited" it) decided to go with those
>> stupid localization complications.
>
> Also, I've never (at home or at work) had any use for any of it.
> Customers have never wanted a user interface not in English, and so
> on.

It's not just that. I have got customers that explicitly wanted
non-english UIs, but that kind of customers systematically want GUIs.
So, the point of localizing printf or std::cout is really non-existing.
It should have been left to application libraries, not in the standard,
same as GUI libraries.

>
> Maybe it was an idea that sounded like a good idea in the 1980s.
> Or maybe it /is/ a good idea in countries where people don't accept
> English as the lingua franca in technology, e.g. France.
>
> To be honest, there is one feature I want, too: I want sorting of
> strings to take my national characters into account ("Öö" would sort
> last). I can get that with LC_COLLATE="sv_SE". But then I get
> things I probably /don't/ want too, such as case-insensitive sort.
> It's a blunt instrument.

That's a good point.

>
>> It has bitten me in the posterior in the form of the precise format that
>> std::atof() accepts depending on the locale (more precisely, the exact
>> character used as the decimal point depends on the locale), which made
>> it completely useless for my purposes (because I wanted to parse
>> floating point values in a fixed format).
>
> Here is another bluntness: sv_SE implements the old 12.345,67 syntax
> for saying 12345.67, but people are just as likely to input 12345.67,
> especially if they're programmers, or have any international contacts
> at all[1]. So you can't always use it in a localized user interface,
> either. Not without annoying people.

Even worse: most non-english keyboards still have a dot in the keypad
instead of a comma (although I have seen some having it in there), so
even for a French user typing 12345,67 is just painful.

Mr Flibble

unread,
Sep 18, 2020, 11:40:31 AM9/18/20
to
Neither (f)printf nor iostreams are suitable for formatted output if such formatting is to include localization support; C++20 fmt should fix this inadequacy.

/Flibble

--
¬

Paavo Helde

unread,
Sep 18, 2020, 1:15:43 PM9/18/20
to
18.09.2020 18:40 Mr Flibble kirjutas:

> Neither (f)printf nor iostreams are suitable for formatted output if
> such formatting is to include localization support; C++20 fmt should fix
> this inadequacy.

So far all my locale-related efforts have been directed to *avoiding*
any locale-specific formatting. Surprisingly difficult at times...

Mr Flibble

unread,
Sep 18, 2020, 1:34:05 PM9/18/20
to
It is an unavoidable fact that different languages have varying grammars resulting in words (nouns, verbs etc) appearing in different relative positions in sentences; this is why (f)printf and iostreams simply do not work; not everyone uses English.

/Flibble

--
¬

Paavo Helde

unread,
Sep 18, 2020, 2:06:49 PM9/18/20
to
I know that :-) Changing the locale to non-English should work like
Babel fish, but somehow it doesn't.

And even if it worked like Babel fish it should not be used when writing
data which will be read by some other software only, not by a human being.

Our software is aimed at PhD level and there have not been any requests
to translate it, even when sold in China. That's just fortunate because
doing a correct translation seems to be a mission impossible (or at
least many times more expensive than the original project) these days,
even if printf or iostreams are not involved. Recent advent of
translation AI seems to make things worse, not better.

Scott Lurndal

unread,
Sep 18, 2020, 2:41:22 PM9/18/20
to
Which is why gettext[*], in combination with printf argument position flags (e.g. %2$u), is
so useful for i18n.

[*] and/or the often proprietary versions in other unix flavors.

Juha Nieminen

unread,
Sep 18, 2020, 3:42:18 PM9/18/20
to
Paavo Helde <ees...@osa.pri.ee> wrote:
>> Extending std::ostream to support your custom type would usually not require
>> such temporary string buffers. Moreover, it grants you access to the
>> std::ostream object itself, giving you the option of *how* to output the
>> data (for example you could use std::ostream::write() instead of the regular
>> operator<<'s). With that scheme you propose you don't have access to the
>> FILE* where you are outputting, and thus you don't have, for example, the
>> option of using std::fwrite() if you so wanted.
>
> I thought we were talking about formatted output, that's what fprintf()
> and streams are all about. I'm curious, how many times have you used
> std::ostream::write() in your operator<< ?

My point is that in the implementation of the operator<<() overload
for your custom type you can use std::ostream::write() to output the
value you want if you so want. Or any of the other functions that
std::ostream offers. (In some cases the write() function could
actually be the *simplest* way of outputing the value. It's also
probably the most efficient, as a bonus.)

You don't have that option in the scenario you suggested.

> Also, I consider it a good thing to modularize the program. Why should
> the code formatting the object content know or care about streams or
> FILE* pointers?

For optimization reasons.

And it's not like a stream-aware printing function and a generic
print-to-string function are mutually exclusive.

>> Also, somewhat ironically, in some cases you would need to resort to
>> stringstreams in order to create the string to be printed.
>
> So what? This is an implementation detail.

I just said it's a bit ironic.

>> Not the only problem. I mentioned the other one: printf() is not generic
>> enough. You can't use it when the type of the value to print is abstracted
>> away (eg. it's a template type parameter). At least not even nearly as
>> easily as with std::ostream.
>
> How comes? If everything supports conversion to strings, it's trivial to
> use in templates. Since C++11 we also have std::to_string() for
> primitive types, so they could be easily incorporated as well if needed.

std::to_string() does not support *any* formatting parameters
(such as printing in hex, or with a minimum width, with or without
leading characters, or the different types of floating point
formats, and so on.) It also doesn't support all primitive types,
most particularly pointers.

With std::ostream using formatting parameters may not be as handy
as with std::printf(), but at least the possibility is there.

Juha Nieminen

unread,
Sep 18, 2020, 3:45:22 PM9/18/20
to
Melzzzzz <Melz...@zzzzz.com> wrote:
> Isn't it that printf can be now implemented in type safe manner?

Not exactly printf, but a very printf-like function yes, indeed.

https://en.cppreference.com/w/cpp/utility/format

Paavo Helde

unread,
Sep 18, 2020, 5:41:16 PM9/18/20
to
18.09.2020 22:41 Juha Nieminen kirjutas:
> Paavo Helde <ees...@osa.pri.ee> wrote:
>>> Extending std::ostream to support your custom type would usually not require
>>> such temporary string buffers. Moreover, it grants you access to the
>>> std::ostream object itself, giving you the option of *how* to output the
>>> data (for example you could use std::ostream::write() instead of the regular
>>> operator<<'s). With that scheme you propose you don't have access to the
>>> FILE* where you are outputting, and thus you don't have, for example, the
>>> option of using std::fwrite() if you so wanted.
>>
>> I thought we were talking about formatted output, that's what fprintf()
>> and streams are all about. I'm curious, how many times have you used
>> std::ostream::write() in your operator<< ?
>
> My point is that in the implementation of the operator<<() overload
> for your custom type you can use std::ostream::write() to output the
> value you want if you so want. Or any of the other functions that
> std::ostream offers. (In some cases the write() function could
> actually be the *simplest* way of outputing the value. It's also
> probably the most efficient, as a bonus.)

Well, I find it ironic that you bring up efficiency in the context of
iostreams, which are for sure the most inefficient way to output
something from a C++ program.

Efficiency is not always the most dominant concern, but when it is you
can bet iostreams are not the solution you are looking for. Just do a
little benchmark and measure string concatenation speed with
stringstream << vs std::string +=. Granted, std::string+= does not do
things like locale support, but when you are concerned about the speed
of output it means no human will look at the output and therefore no
locale-specific behavior is needed or wanted.

Ian Collins

unread,
Sep 18, 2020, 8:46:47 PM9/18/20
to
On 19/09/2020 06:06, Paavo Helde wrote:
>
> Our software is aimed at PhD level and there have not been any requests
> to translate it, even when sold in China. That's just fortunate because
> doing a correct translation seems to be a mission impossible (or at
> least many times more expensive than the original project) these days,
> even if printf or iostreams are not involved. Recent advent of
> translation AI seems to make things worse, not better.

You are lucky there! Our users are machine operators and technicians,
so all the UIs have to be translated for each market - and the are a lot
of them...

Translation is an expensive and time consuming process which has delayed
our product releases on more than one occasion. My team is lucky, all
our UIs are handled by our Android and Web teams.

--
Ian.

Jorgen Grahn

unread,
Sep 19, 2020, 7:18:32 AM9/19/20
to
On Sat, 2020-09-19, Ian Collins wrote:
> On 19/09/2020 06:06, Paavo Helde wrote:
>>
>> Our software is aimed at PhD level and there have not been any requests
>> to translate it, even when sold in China. That's just fortunate because
>> doing a correct translation seems to be a mission impossible (or at
>> least many times more expensive than the original project) these days,
>> even if printf or iostreams are not involved. Recent advent of
>> translation AI seems to make things worse, not better.
>
> You are lucky there! Our users are machine operators and technicians,
> so all the UIs have to be translated for each market - and the are a lot
> of them...

My end users have always fallen in the (broad) "technician" category,
and I have never heard anyone even suggest the /possibility/ of
localization.

> Translation is an expensive and time consuming process which has delayed
> our product releases on more than one occasion. My team is lucky, all
> our UIs are handled by our Android and Web teams.

There's that difference again (someone brought it up earlier): I've
never been involved in anything with a GUI. Plenty of UI, but no GUI.

Maybe localization isn't important to the customers, but their UX experts
insist on it out of habit?

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Juha Nieminen

unread,
Sep 19, 2020, 3:35:28 PM9/19/20
to
Paavo Helde <ees...@osa.pri.ee> wrote:
> Well, I find it ironic that you bring up efficiency in the context of
> iostreams, which are for sure the most inefficient way to output
> something from a C++ program.

How old is the information on which that claim is based?

I myself compared the speed of std::fwrite() vs. std::ostream::write()
and noticed a quite clear difference in favor of the former... something
like 15 years ago.

In order to update my experience I recently tried to repeat the experiment,
but the results were extremely inconclusive because I was unable to get
consistent results. The times I got were all over the place, from run to
run of the exact same binary. (This could be due to a myriad of reasons,
perhaps related to the hardware, the operating system, or the C runtime.
But summa summarum, I couldn't get a definitive answer whether fwrite
is still measurably faster than ostream::write.)

Ian Collins

unread,
Sep 19, 2020, 4:17:42 PM9/19/20
to
On 19/09/2020 23:18, Jorgen Grahn wrote:
> On Sat, 2020-09-19, Ian Collins wrote:
>> On 19/09/2020 06:06, Paavo Helde wrote:
>>>
>>> Our software is aimed at PhD level and there have not been any requests
>>> to translate it, even when sold in China. That's just fortunate because
>>> doing a correct translation seems to be a mission impossible (or at
>>> least many times more expensive than the original project) these days,
>>> even if printf or iostreams are not involved. Recent advent of
>>> translation AI seems to make things worse, not better.
>>
>> You are lucky there! Our users are machine operators and technicians,
>> so all the UIs have to be translated for each market - and the are a lot
>> of them...
>
> My end users have always fallen in the (broad) "technician" category,
> and I have never heard anyone even suggest the /possibility/ of
> localization.

"Technician" in our context are those who calibrate the machines for
customers and operators. This process can be quite complex and any
misunderstandings can have bad consequences...

>> Translation is an expensive and time consuming process which has delayed
>> our product releases on more than one occasion. My team is lucky, all
>> our UIs are handled by our Android and Web teams.
>
> There's that difference again (someone brought it up earlier): I've
> never been involved in anything with a GUI. Plenty of UI, but no GUI.
>
> Maybe localization isn't important to the customers, but their UX experts
> insist on it out of habit?

Not for us; I can't imagine many international construction machine
operators speaking good enough English to work with an English only UI.
It is probably intuitive enough to learn, but localisation is essential
in most markets - can you imagine selling an English only system in France?

--
Ian.

Jorgen Grahn

unread,
Sep 19, 2020, 5:53:17 PM9/19/20
to
I'm pretty sure we did it at my previous workplace, and we're doing it
right now at my current one.

Scott Lurndal

unread,
Sep 20, 2020, 10:46:27 AM9/20/20
to
Juha Nieminen <nos...@thanks.invalid> writes:
>Paavo Helde <ees...@osa.pri.ee> wrote:
>> Well, I find it ironic that you bring up efficiency in the context of
>> iostreams, which are for sure the most inefficient way to output
>> something from a C++ program.
>
>How old is the information on which that claim is based?
>
>I myself compared the speed of std::fwrite() vs. std::ostream::write()
>and noticed a quite clear difference in favor of the former... something
>like 15 years ago.

Well Paavo didn't say "from a standard-compliant C++" program.

read/write/pread/pwrite are much faster than any of the stdio-based
I/O mechanisms. mmap is also much more efficient. For certain
applications direct access to the device (unix raw files, linux O_DIRECT)
are the most efficient ways to access data.

Paavo Helde

unread,
Sep 20, 2020, 11:01:15 AM9/20/20
to
I see somehow we got carried away from formatted ouput (fprintf() and
stream <<) to unformatted output (fwrite and ostream::write).
Unformatted output is faster for sure and fwrite and ostream::write
speeds might indeed be comparable, especially if the buffer sizes are large.

My claims were about formatted stream <<. For some fun I created a
little test program for comparing formatted output of a custom class A
the "official" stream way, and with a ToString() method suitable for
printf-like interfaces. You should need to call it with stdout
redirected to >NUL or >/dev/null, to leave out any console or actual
disk writing overhead.

VC++ 2017, x64 release build:

> test.exe >NUL
temp std::string: 0.478026 s
std::ostream::operator<<() : 3.09337 s

So it appears ToString() is over 6x faster than <<, with VC++.

On the other hand, g++ seems to cope with this test much better and
there the stream << is faster:

Cygwin g++ 9.3, -std=c++17 -O2 :

> ./a.exe >/dev/null
temp std::string: 0.580246 s
std::ostream::operator<<() : 0.364451 s

So maybe you are right in that (some) compiler writers are catching up
and streams are not so slow any more as they used to be. But as VC++ is
one of my major targets I cannot count on it yet.


The test program itself:


#include <string>
#include <cstdio>
#include <chrono>
#include <iostream>
#include <algorithm>
#include <random>

const int n = 1000000;

class A {
std::string name;
std::uint32_t value;
friend std::ostream& operator<<(std::ostream& stream, const A& a);
static std::mt19937 gRnd;
public:
A(): name("A"+std::to_string(gRnd())), value(gRnd()) {}

std::string ToString() const {
return name + ": " + std::to_string(value);
}
};

std::ostream& operator<<(std::ostream& stream, const A& a) {
stream << a.name << ": " << a.value;
return stream;
}

std::mt19937 A::gRnd;

int main() {
std::vector<A> data(n);

auto start1 = std::chrono::steady_clock::now();
for (const A& ref: data) {
printf("%s\n", ref.ToString().c_str());
}
auto finish1 = std::chrono::steady_clock::now();

auto start2 = std::chrono::steady_clock::now();
for (const A& ref: data) {
std::cout << ref << "\n";
}
auto finish2 = std::chrono::steady_clock::now();

fprintf(stderr, "temp std::string: %g s\n",
std::chrono::duration<double>(finish1-start1).count());
fprintf(stderr, "std::ostream::operator<<() : %g s\n",
std::chrono::duration<double>(finish2-start2).count());
}




Jorgen Grahn

unread,
Sep 20, 2020, 1:38:19 PM9/20/20
to
On Sun, 2020-09-20, Scott Lurndal wrote:
> Juha Nieminen <nos...@thanks.invalid> writes:
>>Paavo Helde <ees...@osa.pri.ee> wrote:
>>> Well, I find it ironic that you bring up efficiency in the context of
>>> iostreams, which are for sure the most inefficient way to output
>>> something from a C++ program.
>>
>>How old is the information on which that claim is based?
>>
>>I myself compared the speed of std::fwrite() vs. std::ostream::write()
>>and noticed a quite clear difference in favor of the former... something
>>like 15 years ago.
>
> Well Paavo didn't say "from a standard-compliant C++" program.
>
> read/write/pread/pwrite are much faster than any of the stdio-based
> I/O mechanisms.

Not if you end up writing a byte (or a few bytes) at a time -- which
is part of the reason stdio exists.

(I haven't checked recently, but I guess system calls are still not
cheap.)

I haven't followed this thread closely, but it seems a bit
oversimplified to me. It would be easier to discuss a real-life case
where stream output /is/ a bottleneck, and then see what to do about
it.

Jorgen Grahn

unread,
Sep 20, 2020, 1:59:29 PM9/20/20
to
On Sun, 2020-09-20, Paavo Helde wrote:
...

> I see somehow we got carried away from formatted ouput (fprintf() and
> stream <<) to unformatted output (fwrite and ostream::write).
> Unformatted output is faster for sure and fwrite and ostream::write
> speeds might indeed be comparable, especially if the buffer sizes are large.
>
> My claims were about formatted stream <<. For some fun I created a
> little test program for comparing formatted output of a custom class A
> the "official" stream way, and with a ToString() method suitable for
> printf-like interfaces. You should need to call it with stdout
> redirected to >NUL or >/dev/null, to leave out any console or actual
> disk writing overhead.

On Linux I often pipe the output to md5sum or similar, so I can be
sure it doesn't change between runs.

> VC++ 2017, x64 release build:
>
> > test.exe >NUL
> temp std::string: 0.478026 s
> std::ostream::operator<<() : 3.09337 s
>
> So it appears ToString() is over 6x faster than <<, with VC++.
>
> On the other hand, g++ seems to cope with this test much better and
> there the stream << is faster:
>
> Cygwin g++ 9.3, -std=c++17 -O2 :
>
> > ./a.exe >/dev/null
> temp std::string: 0.580246 s
> std::ostream::operator<<() : 0.364451 s

Debian Stable: I get roughly the same figures for both.

> So maybe you are right in that (some) compiler writers are catching up
> and streams are not so slow any more as they used to be. But as VC++ is
> one of my major targets I cannot count on it yet.

(You can, if formatted output is not the bottleneck in your programs.)

> The test program itself:
...

You should probably have used 'std::cout.sync_with_stdio(false)' here
too. I added it and, oddly, it didn't make any difference for
performance, but I could see from 'strace -c' that the std::cout code
path changed: in terms of system calls it used writev(2) instead of
write(2), and it wrote twice as much at each call.

I have seen that flag make a big difference in the past (i.e. a decade
ago).

Paavo Helde

unread,
Sep 21, 2020, 1:28:17 AM9/21/20
to
20.09.2020 20:59 Jorgen Grahn kirjutas:
>
> You should probably have used 'std::cout.sync_with_stdio(false)' here
> too. I added it and, oddly, it didn't make any difference for
> performance, but I could see from 'strace -c' that the std::cout code
> path changed: in terms of system calls it used writev(2) instead of
> write(2), and it wrote twice as much at each call.

FWIW, I tried to call sync_with_stdio(false) as well, but it did not
make any significant difference with VC++ either.

Richard

unread,
Sep 21, 2020, 7:50:27 PM9/21/20
to
[Please do not mail me a copy of your followup]

Jorgen Grahn <grahn...@snipabacken.se> spake the secret code
<slrnrm7glh.8...@frailea.sa.invalid> thusly:

>Also, I've never (at home or at work) had any use for any of it.
>Customers have never wanted a user interface not in English, and so
>on.

Consider yourself lucky. I've worked on code bases that were
localized into 14 languages.

You almost certainly need to localize your application if you attempt
any significant amount of sales in Japan. They're pretty insistent
about that.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Andrey Tarasevich

unread,
Sep 25, 2020, 2:30:09 AM9/25/20
to
On 9/16/2020 12:16 PM, Mr Flibble wrote:
> Just submitted a VS2019 bug report (C++17 non-conformance):
>
> std::cout << a() << "," << b(); // a() is not sequenced before b()
>
> /Flibble

It is 2020 already and nobody seems to have gotten it quite right yet.
New C++17 sequencing rules remain largely un-/under-implemented in GCC
and Clang too.

#include <cstdint>
#include <iostream>

uint16_t foo(uint16_t abgr)
{
return (abgr ^= (abgr >> 8)) ^= (abgr << 8);
}

int main()
{
uint16_t tmp = 0xAABB;
std::cout << std::hex << tmp << " " << foo(tmp) << std::endl;
}

The result for 'foo(tmp)' is unambiguously defined: it shall be '0x1111'
and nothing else.

GCC produces '0xBB11', which is an instant fail. Clang produces the
correct result, but spews a completely unjustified sequencing warning
(albeit it seems that they finally got rid of it in version 10). MSVC++
produces the correct result and doesn't seem to complain.

--
Best regards,
Andrey Tarasevich

Ben Bacarisse

unread,
Sep 25, 2020, 10:45:44 AM9/25/20
to
Andrey Tarasevich <andreyta...@hotmail.com> writes:

> On 9/16/2020 12:16 PM, Mr Flibble wrote:
>> Just submitted a VS2019 bug report (C++17 non-conformance):
>>
>> std::cout << a() << "," << b(); // a() is not sequenced before b()
>>
>> /Flibble
>
> It is 2020 already and nobody seems to have gotten it quite right
> yet. New C++17 sequencing rules remain largely un-/under-implemented
> in GCC and Clang too.
>
> #include <cstdint>
> #include <iostream>
>
> uint16_t foo(uint16_t abgr)
> {
> return (abgr ^= (abgr >> 8)) ^= (abgr << 8);
> }
>
> int main()
> {
> uint16_t tmp = 0xAABB;
> std::cout << std::hex << tmp << " " << foo(tmp) << std::endl;
> }
>
> The result for 'foo(tmp)' is unambiguously defined: it shall be
> '0x1111' and nothing else.

I don't follow. The two shift operators are not sequenced in relation
to each other. The new C++17 rules for << and >> have no effect here as
neither operand has any side effects. Have I missed some broader rule
change?

--
Ben.

Juha Nieminen

unread,
Sep 25, 2020, 11:12:51 AM9/25/20
to
Andrey Tarasevich <andreyta...@hotmail.com> wrote:
> It is 2020 already and nobody seems to have gotten it quite right yet.

Not getting something right about the C++17 standard is one thing.
How about, in 2020, not getting something right about the C++98
standard?

These two function declarations should be considered *different*
functions:

extern "C" using c_func = int(const void*, const void*);
extern "C++" using cpp_func = int(const void*, const void*)

These should be considered *different* overloads, ie. different
functions:

void foo(c_func*);
void foo(cpp_func*);

There's a bug report made in 2001 about gcc 2.97 about this issue,
which still hasn't been fixed in 2020 in gcc 10.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316

Other compilers aren't much better about this.

Tim Rentsch

unread,
Sep 25, 2020, 12:31:14 PM9/25/20
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:

> Andrey Tarasevich <andreyta...@hotmail.com> writes:
>
>> On 9/16/2020 12:16 PM, Mr Flibble wrote:
>>
>>> Just submitted a VS2019 bug report (C++17 non-conformance):
>>>
>>> std::cout << a() << "," << b(); // a() is not sequenced before b()
>>
>> It is 2020 already and nobody seems to have gotten it quite right
>> yet. New C++17 sequencing rules remain largely un-/under-implemented
>> in GCC and Clang too.
>>
>> #include <cstdint>
>> #include <iostream>
>>
>> uint16_t foo(uint16_t abgr)
>> {
>> return (abgr ^= (abgr >> 8)) ^= (abgr << 8);
>> }
>>
>> int main()
>> {
>> uint16_t tmp = 0xAABB;
>> std::cout << std::hex << tmp << " " << foo(tmp) << std::endl;
>> }
>>
>> The result for 'foo(tmp)' is unambiguously defined: it shall be
>> '0x1111' and nothing else.
>
> I don't follow. The two shift operators are not sequenced in relation
> to each other. The new C++17 rules for << and >> have no effect here as
> neither operand has any side effects. Have I missed some broader rule
> change?

In C++17, assignment operators (including ^=, etc) specify that the
right operand is sequenced before the left operand. Hence the
outermost ^= causes the << to be sequenced before the inner ^=
expression.

Andrey Tarasevich

unread,
Sep 25, 2020, 1:00:55 PM9/25/20
to
The key moment here is the new sequencing rules for assignment
operators, not for `<<`.

All assignment operators (including compound assignment) became very
tightly sequenced in C++17. Right-hand side is fully sequenced before
the left-hand size. The actual side effect (of assignment) takes place
before value-evaluation of the assignment-expression.

And this is what produces unambiguous sequencing of the shifts relative
to each other in the above example.

The '[]' operator is also sequenced now, and if I recall correctly this
is still glitchy in GCC.

Andrey Tarasevich

unread,
Sep 25, 2020, 2:10:48 PM9/25/20
to
On 9/16/2020 12:16 PM, Mr Flibble wrote:
> Just submitted a VS2019 bug report (C++17 non-conformance):
>
> std::cout << a() << "," << b(); // a() is not sequenced before b()
>

#include <iostream>

int main()
{
int i = 0;
std::cout << ++i << ++i << std::endl;
}

Compiling in GCC 10.2 with '-Wall -std=c++17'

warning: operation on 'i' may be undefined [-Wsequence-point]
std::cout << ++i << ++i << std::endl;
^~~

Compiling in Clang 10.0.1 with '-Wall -std=c++17'

warning: multiple unsequenced modifications to 'i' [-Wunsequenced]
std::cout << ++i << ++i << std::endl;
^ ~~

While both compilers produce the correct output, the above diagnostic
messages suggest that this is purely a coincidence. C++17 is still not
quite there in any of the current mainstream compilers. In many (if not
most) respects VS2019 looks well ahead of the pack.

Ben Bacarisse

unread,
Sep 25, 2020, 3:29:59 PM9/25/20
to
Ah, right. I missed that change (and I thought this was a follow on
from the << discussion so I didn't check). My mistake.

FWIW, g++ 9.3.0-17ubuntu1~20.04 produces 0x1111.

--
Ben.

Manfred

unread,
Sep 27, 2020, 11:27:00 AM9/27/20
to
gcc 10.2.1 still gives 0xBB11

I think it would be wise for the OP to file a bug to gcc.

0 new messages