Tuesday, February 23, 2016

Digest for comp.lang.c++@googlegroups.com - 25 updates in 7 topics

Vir Campestris <vir.campestris@invalid.invalid>: Feb 23 09:42PM

On 21/02/2016 21:15, Alf P. Steinbach wrote:
 
> Oh, they're C++11 user defined literals.
 
<snip>
 
> Cheers & hth.,
 
It helps a lot. Thanks! Shame I'm writing a lot of C these days...
 
Andy
bitrex <bitrex@de.lete.earthlink.net>: Feb 23 02:17PM -0500

Does anyone know if the following "naughty" (implementation dependent)
construct would work "correctly" on the ARM Cortex M4, compiled with
arm-gcc-embedded?
 
typedef union {
uint32_t phase_accumulator_full;
struct {
uint8_t integer_high : 8,
integer_low : 8,
frac_high : 8,
frac_low : 8;
 
};
} phase_accumulator;
John Devereux <john@devereux.me.uk>: Feb 23 07:36PM

> frac_low : 8;
 
> };
> } phase_accumulator;
 
I am not an expert (ask on comp.arch.embedded) but my understanding is
that this sort of thing is guaranteed by the EABI (bugs aside).
 
 
 
--
 
John Devereux
David Brown <david.brown@hesbynett.no>: Feb 23 10:34PM +0100

On 23/02/16 20:36, John Devereux wrote:
>> } phase_accumulator;
 
> I am not an expert (ask on comp.arch.embedded) but my understanding is
> that this sort of thing is guaranteed by the EABI (bugs aside).
 
I can't even figure out why it would be considered "naughty" at all.
The only implementation-dependent aspects I can see are the alignment of
the parts (on the ARM, 8-bit, 16-bit and 32-bit types all have "natural"
alignments), and the ordering of the bitfields (which is low bits first
- guaranteed by the ARM EABI, and thus consistent across compilers).
Jerry Stuckle <jstucklex@attglobal.net>: Feb 23 11:21AM -0500

On 2/23/2016 9:43 AM, David Brown wrote:
 
> No, the post here was /not/ what I expect from people in this group -
> that is why I react against it. I don't think it really counts as
> trolling either. I am not sure /what/ it counts as, but I don't like it.
 
It is trolling, plain and simple, according to the commonly used
definition for the last 20+ years. As are twisting people's words,
ignoring facts someone else posts and other things I've seen in this group.
 
Maybe you don't think it's trolling. But this post does not surprise me
in the least. And the poster was even too chicken to use his own name.
Just another proof of trolls being here.
 
--
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================
Paavo Helde <myfirstname@osa.pri.ee>: Feb 23 06:23PM +0200

On 23.02.2016 10:16, David Brown wrote:
 
> But such checks are not constant expressions - you cannot use the result
> in things like static initialisers, constexpr expressions, static
> asserts, #if directives, etc.
 
Are these constexpr limitations (like banning reinterpret_cast) there
because of cross-compilation? Is it that if reinterpret_cast were
allowed in constexpr, the compiler would need to emulate the target
processor, whereas by current rules it only has to calculate the correct
portable value?
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 23 07:15PM +0100

On 23.02.2016 09:01, Paavo Helde wrote:
> possible to reuse the user literal mechanism itself, even if it is not
> good for finding out the actual endianness it should be good for the
> user literals themselves.
 
If that were possible then it could serve as a way to determine
endianness, which would be great.
 
 
> (Warning: I do not have access to any big- or mixed-endian machines for
> testing, so this may contain bugs, and certainly it can be simplified):
 
I suspect that this is a late-night posting.
 
I sometimes do that. ;-)
 
Happily the net is full of critics.
 
 
> }
> }
> }
 
Okay, let's first examine
 
constexpr uint64_t operator""_idraw(const char* p, size_t n) {
return static_cast<unsigned char>(*p) | (n>0 ?
operator""_idraw(p+1, n-1): uint64_t(0))<<8;
}
 
constexpr uint64_t SelectByte(int pos) {
return
pos==0 ? "\xff"_idraw :
(pos==1 ? "\x00\xff"_idraw :
(pos==2 ? "\x00\x00\xff"_idraw :
(pos==3 ? "\x00\x00\x00\xff"_idraw :
(pos==4 ? "\x00\x00\x00\x00\xff"_idraw :
(pos==5 ? "\x00\x00\x00\x00\x00\xff"_idraw :
(pos==6 ? "\x00\x00\x00\x00\x00\x00\xff"_idraw :
(pos==7 ? "\x00\x00\x00\x00\x00\x00\x00\xff"_idraw : 0)))))));
}
 
This can be replaced with just
 
constexpr uint64_t SelectByte(int pos) {
return (pos >= 8? 0 : uint64_t( 0xFF ) << 8*pos);
}
 
That's a good code transformation, I think. :)
 
Then this:
 
constexpr uint64_t Fill64(uint64_t c) {
return c | c<<8 | c<<16 | c<<24 | c<<32 | c<<40 | c<<48 | c<<56;
}
 
constexpr uint64_t SelectByte(int pos) {
return (pos >= 8? 0 : uint64_t( 0xFF ) << 8*pos);
}
 
constexpr uint64_t IdFromString(const char* p, size_t n, int pos) {
return (Fill64(static_cast<unsigned char>(*p)) &
SelectByte(pos)) | (n>0 ? IdFromString(p+1, n-1, pos+1) : uint64_t(0));
 
… can be replaced with just
 
 
constexpr
auto left_shifted( unsigned char const val, int const distance )
-> uint64_t
{ return (distance >= 64? 0 : uint64_t( val ) << distance); }
 
constexpr uint64_t IdFromString(const char* p, size_t n, int pos) {
return left_shifted( *p, 8*pos ) | (n>0 ? IdFromString(p+1,
n-1, pos+1) : uint64_t(0));
}
 
And at this point it's clear that the code does an endian-agnostic
conversion from a base 256 number specification, to number, just as the
earlier programs.
 
• • •
 
The endianness issue can instead be addressed in the `StrFromId`
function, where one is not constrained by the `constexpr` limitations.
 
E.g. a strategic little call to `std::reverse` will do the trick.
 
 
Cheers!,
 
- Alf
Paavo Helde <myfirstname@osa.pri.ee>: Feb 23 09:40PM +0200

On 23.02.2016 20:15, Alf P. Steinbach wrote:
 
>> (Warning: I do not have access to any big- or mixed-endian machines for
>> testing, so this may contain bugs, and certainly it can be simplified):
 
> I suspect that this is a late-night posting.
 
No, this was an early-morning posting before sufficient coffee intake ;-)
 
 
> And at this point it's clear that the code does an endian-agnostic
> conversion from a base 256 number specification, to number, just as the
> earlier programs.
 
Yeah, I was having a growing suspicion of the same ...
 
> The endianness issue can instead be addressed in the `StrFromId`
> function, where one is not constrained by the `constexpr` limitations.
 
True, but I think someone wanted to see the strings in memory while
debugging. But for that purpose the endianness is in practice easily
detected by the relevant macros and in the remote chance the program
gets it wrong then it is easy enough to fix and recompile.
 
Anyway, thanks for demolishing my monster!
Paavo
David Brown <david.brown@hesbynett.no>: Feb 23 10:29PM +0100

On 23/02/16 17:23, Paavo Helde wrote:
> allowed in constexpr, the compiler would need to emulate the target
> processor, whereas by current rules it only has to calculate the correct
> portable value?
 
I don't know. I suspect it is more of a historical limitation - there
are many things that a modern compiler can calculate at compile time,
which early compilers could not do. If something is legal as a constant
expression, then any compiler, even an unsophisticated and unoptimising
one, has to figure it out at compile time - otherwise you would end up
with code that was legal on one compiler and illegal on another one. I
suppose the standards /could/ say "whether an expression using a
reinterpret_cast is a constant expression or not is implementation
dependent", but I think that would add a good deal of complications to
the language.
 
But Jerry is going to show us a compile-time constant expression to
detect endianness using pure standard C++, so that will settle the matter.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 23 07:45PM +0100

On 23.02.2016 10:55, bartekltg wrote:
 
>> There is a C++ standard library header <complex>. It's different from
>> <ccomplex> and <complex.h>.
 
> It has changed ;-)
 
No. Not as far as I know. :)
 
 
> "26.4.11 Header <ccomplex> [ccmplx]
> 1 The header behaves as if it simply includes the header <complex>."
 
Points to understand the above quote, which is of C++11 §26.4.10/1:
 
• The header <ccomplex> is not the header <complex>.
 
• The header <ccomplex> is the basic C++ variant of the /C header/
<complex.h>. It places the C declarations in namespace std. It may also
place them in the global namespace.
 
• The /C++ header/ <complex.h>, distinct from the C header <complex.h>
(same name, yes), is defined in terms of <ccomplex> instead of directly
in terms of the C header. The C++ header <complex.h> provides the same
contents as <ccomplex> except that it provides this content in the
global namespace. It may also provide the contents in the std namespace.
 
And yes, I agree, the complexity of this is really ridiculous. The
original C++98 idea was evidently to not-so-subtly-at-all encourage a
move from "foo.h" headers to header names without filename extensions
"cfoo". At that time C++ <ccomplex> was not allowed to pollute the
global namespace. But that did not sit well with compiler vendors, who
saw no reason to jump through hoops with additional extreme complexity,
with no evident advantage other than maybe supporting some idealistic
notions about filenames, so with C++11 the rules were changed to make
the <ccomplex> and <complex.h> requirements symmetric (and ditto for all
other such header pairs), incidentally making the whole thing
/meaningless/. So, just include <complex.h>, and forget about the
<ccomplex> complexity, so to speak – but remember that this is the
/C++ version/ of <complex.h>, and so it can, at the implementation's
discretion, make code that uses std:: qualifications compile, even
though that will not compile with some other compiler. :(
 
Relevant:
 
C++11 §17.6.1.2:
 
<quote>
Except as noted in Clauses 18 through 30 and Annex D, the contents of
each header cname shall be the same as that of the corresponding header
name.h, as specified in the C standard library (1.2) or the C Unicode
TR, as appropriate, as if by inclusion. In the C ++ standard library,
however, the declarations (except for names which are defined as macros
in C) are within namespace scope (3.3.6) of the namespace std. It is
unspecified whether these names are first declared within the global
namespace scope and are then injected into namespace std by explicit
using-declarations (7.3.3).
</quote>
 
 
> (4.5) — reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the
> imaginary part of a[i].
> "
 
Yes. That compatibility is the whole point of the above wording.
 
 
> I think the problem is with libraries based on fortran (with C
> interface). Then reinterpreted cast is needed, but at least
> should work.
 
Oh. I didn't think of that.
 
 
Cheers!,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 23 07:55PM +0100

Oh, please disregard that posting, I was not thinking clearly.
 
There is no way there can be a C++ version of C99 <complex.h>, due to
the C99 keyword _Complex.
 
:(
 
 
Cheers,
 
- Alf
 
 
On 23.02.2016 19:45, Alf P. Steinbach wrote:
bartekltg <bartekltg@gmail.com>: Feb 23 08:41PM +0100

On 23.02.2016 19:45, Alf P. Steinbach wrote:
>>> <ccomplex> and <complex.h>.
 
>> It has changed ;-)
 
> No. Not as far as I know. :)
 
In gcc 5.2.1, ccomplex:
 
#pragma GCC system_header
 
#ifndef _GLIBCXX_CCOMPLEX
#define _GLIBCXX_CCOMPLEX 1
 
#if __cplusplus < 201103L
# include <bits/c++0x_warning.h>

No comments: