Tuesday, November 6, 2018

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

Keith Thompson <kst-u@mib.org>: Nov 05 06:00PM -0800

David Brown <david.brown@hesbynett.no> writes:
[...]
> bits are unused - but they still take up space in the struct, and still
> affect alignment.
 
> If you want this all to be within a 16-bit struct, use u16 (or uint16_t).
[...]
> The size (and alignment) comes from the size of the underlying type,
> which is 32-bit in this case.
 
The standard says that allocation of bit-fields is
implementation-defined. I don't see anything in the standard that
implies either that there is, or that there isn't, any difference
between, for example,
int8_t bitfield : 5;
and
int32_t bitfield : 5;
though I think some ABIs impose more specific requirements.
 
--
Keith Thompson (The_Other_Keith) kst@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 05 06:53PM -0800

On Monday, November 5, 2018 at 9:00:18 PM UTC-5, Keith Thompson wrote:
> int8_t bitfield : 5;
> and
> int32_t bitfield : 5;
 
+1.
 
> though I think some ABIs impose more specific requirements.
 
They'd have no choice, but to compute the two examples above
for sizeof() to be int8_t = 1 and int32_t = 4 is just wrong
on every level.
 
--
Rick C. Hodgin
David Brown <david.brown@hesbynett.no>: Nov 06 10:49AM +0100

On 06/11/18 03:00, Keith Thompson wrote:
> and
> int32_t bitfield : 5;
> though I think some ABIs impose more specific requirements.
 
Certainly it is common for ABI's (or compiler implementations) to use
the declared underlying type for allocation sizes and alignments. It is
also common in embedded systems (where bitfields and volatile are
common) to insist that the compiler respects the access size when
dealing with volatile structs with bitfields.
 
But as for the standards, I don't see it clearly expressed - so it does
not seem to be a requirement. It talks about "the addressable storage
unit holding the bit-field", and C11 6.7.2.1 describes how packing of
bits within these units is to be done (with plenty of room for
implementation defined behaviour). There does not appear to be anything
saying that the "addressable storage unit" here has to be of the size
and type of the bit-field's type - indeed, "An implementation may
allocate any addressable storage unit large enough to hold a bit-field".
 
However, the usefulness of bit-fields for "conforming to externally
imposed layouts" would be hindered if the implementation did not give
the programmer control over the sizes here.
 
Older C compilers sometimes had support for only "signed int" and
"unsigned int" as bit-field types - most that I have used in the past
couple of decades have supported a range of types. It is certainly
possible that compilers with only "int" and "unsigned int" as types
would have used smaller underlying storage units, while I think more
modern ones use the type you ask for. But it is, naturally,
implementation-dependent.
 
(I have looked through the C++ standards too, and didn't see any
difference here.)
David Brown <david.brown@hesbynett.no>: Nov 06 10:57AM +0100

On 06/11/18 03:53, Rick C. Hodgin wrote:
>> and
>> int32_t bitfield : 5;
 
> +1.
 
It looks like the standards don't impose rules here, but ABI's and
implementations do.
 
 
> They'd have no choice, but to compute the two examples above
> for sizeof() to be int8_t = 1 and int32_t = 4 is just wrong
> on every level.
 
No, it is certainly not wrong according to the C (or C++) standards, nor
is it wrong according to the ABI's of many processors and C
implementations. And speaking as someone who uses bitfields regularly
in cases where exact layouts and accesses are important, it is often
/essential/ that the type of the bitfield be used for the size,
alignment and accesses.
 
It is extremely simple to get the layout you want - use an appropriately
sized underlying type. (Yes, support for that is
implementation-dependant - but so are most things regarding bit-fields.)
"Öö Tiib" <ootiib@hot.ee>: Nov 06 03:08AM -0800

On Tuesday, 6 November 2018 11:57:41 UTC+2, David Brown wrote:
 
> It is extremely simple to get the layout you want - use an appropriately
> sized underlying type. (Yes, support for that is
> implementation-dependant - but so are most things regarding bit-fields.)
 
When it is "extremely simple" (just implementation dependent) then there
must be is a standard compliant way to static assert that we got the layout
that we wanted. Is there such a way?
David Brown <david.brown@hesbynett.no>: Nov 06 12:17PM +0100

On 06/11/18 12:08, Öö Tiib wrote:
 
> When it is "extremely simple" (just implementation dependent) then there
> must be is a standard compliant way to static assert that we got the layout
> that we wanted. Is there such a way?
 
Lots of things in C and C++ sound extremely simple, and are extremely
simple to describe - yet turn out to be really hard with nothing but
standard compliant code!
 
Here I'd say a static assert on the sizeof the struct was the best you
can do - that would likely fail if you've made incorrect assumptions
about the layout. But it won't cover everything, and it certainly won't
cover the order of the bit-fields.
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 06 04:43AM -0800

On Tuesday, November 6, 2018 at 4:57:41 AM UTC-5, David Brown wrote:
 
> It is extremely simple to get the layout you want - use an appropriately
> sized underlying type. (Yes, support for that is
> implementation-dependant - but so are most things regarding bit-fields.)
 
Have you ever seen the movie [Ice Station Zebra]? In my best Russian
accent: "And now I must tell you how wrong you are."
 
The bit expression is a bit expression. And, if you truly need something
like Ian's 13-bit packed data structs, use interleaving structs
which begin at byte boundaries and ignore the previous portions
from prior structs. But the sizeof() a bit packed struct should
be rounded to the nearest larger byte.
 
The expressed type of those bits should not affect in any way the
sizeof() operation. It should always report its byte size occupancy
as rounded up to the nearest byte.
 
Only when I use sizeof(bitstruct.member) should it report the sizeof()
that type.
 
It's just flatly wrong... and now I have to support this failure
in philosophy in CAlive for compatibility.
 
To quote C3PO: "Oooh. How horrid."
 
--
Frederick Clarkson Hodgin, III
 
PS - Bonus points if you can figure out how they got "Rick" from that.
Juha Nieminen <nospam@thanks.invalid>: Nov 06 01:37PM

> When it is "extremely simple" (just implementation dependent) then there
> must be is a standard compliant way to static assert that we got the layout
> that we wanted. Is there such a way?
 
There aren't always ways to static_assert such things.
 
For example, there is no standard-compliant way to static_assert that
we are compiling for a little-endian system, for instance. (This might
be on purpose.)
"Öö Tiib" <ootiib@hot.ee>: Nov 06 06:01AM -0800

On Tuesday, 6 November 2018 15:38:02 UTC+2, Juha Nieminen wrote:
 
> For example, there is no standard-compliant way to static_assert that
> we are compiling for a little-endian system, for instance. (This might
> be on purpose.)
 
I really can't imagine purpose. For example:
 
| C99 6.4.4.4p10: "The value of an integer character constant containing
| more than one character (e.g., 'ab'), or containing a character or escape
| sequence that does not map to a single-byte execution character, is
| implementation-defined."
 
Why? Who benefits from such a wasted feature? That could be defined
to follow order of bytes on platform.
David Brown <david.brown@hesbynett.no>: Nov 06 03:02PM +0100

On 06/11/18 13:43, Rick C. Hodgin wrote:
> which begin at byte boundaries and ignore the previous portions
> from prior structs. But the sizeof() a bit packed struct should
> be rounded to the nearest larger byte.
 
You write that as though it was some sort of indisputable fact. It is
not fact, and it is not indisputable - it is nothing more than your idea
of what you think would be best. It is, of course, fine to have your
opinion - but realise that it is /your/ opinion, and it does not appear
to match the opinion of people making or using C compilers. In
particular, the idea that there is one fixed "right" way to do things
here simply has no anchoring in reality.
 
If you want to use bit-fields, you need to be very careful to check the
layout matches what you want. Don't assume anything, don't assume
consistency between systems. And test rigorously.
 
Some ABIs will define the bit-field layout exactly - some compilers may
not follow these ABIs exactly. Compilers can have options that affect
the layout, and can have extensions ("packed" attributes or pragmas)
that affect them.
 
From a bit of experimenting on godbolt.org, I only found one compiler
for which this struct was not the same size as "int" :
 
struct A {
int x : 1;
int y : 2;
}
 
That was the AVR, which is an 8-bit microcontroller, where you usually
want to save ram. It used one byte for A. (The AVR is also the only
compiler here where the alignment of "int" is less than its size. Being
8-bit, there are no benefits in having larger alignments for any type.)
The msp430 compiler, being a 16-bit device, used 2 bytes. All the rest
used 4.
 
 
> The expressed type of those bits should not affect in any way the
> sizeof() operation. It should always report its byte size occupancy
> as rounded up to the nearest byte.
 
Again, that is an assertion without justification and without foundation
in reality. That is, quite simply, not the case in practice.
 
> Only when I use sizeof(bitstruct.member) should it report the sizeof()
> that type.
 
That is not allowed at all in C or C++. (It would not be unreasonable
to have some sort of "bitsizeof" operator here, but it does not exist in
C or C++.)
 
 
> It's just flatly wrong... and now I have to support this failure
> in philosophy in CAlive for compatibility.
 
I think you overrate your opinions. Does it never occur to you that
when other tools handle something differently, it is /you/ that is
wrong? Alternatively, perhaps it simply doesn't matter that much -
people manage to get what they need? We are not talking about a
complicated or unintuitive workaround here - you want everything to fit
in a 16-bit struct, so use 16-bit types instead of 32-bit types.
 
What you can be sure of, is that however you implement things in your
own language, it will be in conflict with the way bit-fields work with
some compilers.
 
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 06 06:08AM -0800

On Tuesday, November 6, 2018 at 9:02:38 AM UTC-5, David Brown wrote:
> > But the sizeof() a bit packed struct should
> > be rounded to the nearest larger byte.
 
> You write that as though it was some sort of indisputable fact.
 
It is.
 
> > sizeof() operation. It should always report its byte size occupancy
> > as rounded up to the nearest byte.
 
> Again, that is an assertion...
 
Again, it is. And I'm amazed to find so many compiler authors
doing it wrong.
 
Bitfield structs require some special attention. The question
exists in how can I inquire at runtime the sizeof() the bits
in the bitfield, compared to the sizeof() the type it represents,
compared to the sizeof() the entire bitfield struct, compared to
the size of the entire structure expanded to its expressed types.
 
I think bitfield structs are not yet completely cooked in the
existing compilers. Just enough to get it close, but they didn't
bring it to a close.
 
--
Rick C. Hodgin
David Brown <david.brown@hesbynett.no>: Nov 06 03:40PM +0100

On 06/11/18 15:08, Rick C. Hodgin wrote:
>>> be rounded to the nearest larger byte.
 
>> You write that as though it was some sort of indisputable fact.
 
> It is.
 
This is like arguing with a wall.
 
Look, your opinion does not match that of compiler writers, ABI
designers, language designers or programmers. These folks have come to
different conclusions about the best way to implement bit-fields - not
always to the same conclusions, but often different from yours.
 
You are not smarter than these folks. You are not able to see something
that they are missing. You are not able to divine some sort of
"fundamental" issue to which they are blind. You are simply a developer
with an opinion (which is fine), and an over-inflated sense of the value
of that opinion (which is not fine).
 
> in the bitfield, compared to the sizeof() the type it represents,
> compared to the sizeof() the entire bitfield struct, compared to
> the size of the entire structure expanded to its expressed types.
 
You can't - not with standard C or C++, and not with any existing
extensions I am aware of. People have programmed in C for 40 years
without such features, so I don't think the need of them is particularly
pressing. But if you feel they would be useful, put them into your own
language. (I have often felt that a bit more introspection capabilities
in C and C++ would be nice, though I have never felt the need of it for
bit-fields.)
 
(There is a proposal for adding introspection to C++, but that is going
to be a much bigger feature.)
 
> I think bitfield structs are not yet completely cooked in the
> existing compilers. Just enough to get it close, but they didn't
> bring it to a close.
 
Bit-fields certainly have their limitations, and their loose
implementation-defined nature makes them difficult for portability.
With appropriate care, they have their place in programming, and many
people use them. But when designing a new language with different
requirements than C, it may make sense to create an alternative with
much stricter rules.
"Rick C. Hodgin" <rick.c.hodgin@gmail.com>: Nov 06 06:49AM -0800

On Tuesday, November 6, 2018 at 9:40:30 AM UTC-5, David Brown wrote:
 
> You can't - not with standard C or C++, and not with any existing
> extensions I am aware of. People have programmed in C for 40 years
> without such features...
 
An oversight by all to be sure.
 
They're not pressing, but you can't even obtain that information in
today's compilers. It is most definitely an oversight.
 
You say talking to me is like talking to a wall? I just happen to
know I'm right. And today I've added bounce structs to CAlive to
allow reflection mirrors of the bitfield types into their native
types, and back again. I'll also allow the sizeof() to return the
size in bytes, and the bitsizeof() to return the size in bits, and
that will be globally, not just on bitfield structs or members.
 
Good day, David.
 
--
Rick C. Hodgin
Juha Nieminen <nospam@thanks.invalid>: Nov 06 07:13AM

>>anymore?
 
> Yes. The Unisys clearpath dorado systems decended from the Sperry/Univac 1100
> come to mind immediately.
 
Does it even have a modern C++ compiler? Does anybody even know how to use
such a thing?
David Brown <david.brown@hesbynett.no>: Nov 06 10:19AM +0100

On 05/11/18 21:21, Juha Nieminen wrote:
>> Are you sure that CHAR_BIT, the number of bits per byte, equals 8?
 
> Does any computer system where CHAR_BIT isn't 8 even running
> anymore?
 
There are three kinds of systems that have CHAR_BIT > 8 :
 
1. Dinosaur mainframes. There are not many of these still in action,
but they do exist. I don't know if there is much C++ on such systems -
COBOL is more likely.
 
2. Very niche processors and DSP's with very odd byte sizes. If you are
not in the business of custom ASIC systems, you will never come across
them - and your code will never be used on them. Even in the embedded
world, these things are unusual. You'll be using a specialised C
compiler or assembly, not C++.
 
3. General purpose DSP's with 16-bit or 32-bit char, like TI TMS320F2xxx
or Analog Devices SHARC. I believe some of these can be programmed in
C++ these days, but they have fallen out of style for anything but
specialised DSP applications like audio or video codecs.
 
I think it is fair to say that if your code would ever be running on
something that has CHAR_BIT not equal to 8, you would know it.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Nov 06 12:27PM +0100

On 05.11.2018 21:21, Juha Nieminen wrote:
>> Are you sure that CHAR_BIT, the number of bits per byte, equals 8?
 
> Does any computer system where CHAR_BIT isn't 8 even running
> anymore?
 
Embedded computing stuff. E.g. Texas Instruments digital signal processors.
 
 
Cheers!,
 
- Alf
Juha Nieminen <nospam@thanks.invalid>: Nov 06 01:33PM

> I think it is fair to say that if your code would ever be running on
> something that has CHAR_BIT not equal to 8, you would know it.
 
That being said, the way I presented the solution would still work
even if CHAR_BIT is larger than 8. (Every element of the vector is
handled as it if were 8 bits in size, but there's nothing that would
break if it were larger.)
 
It would only malfunction if CHAR_BIT is less than 8. The assumption
I made in the solution I presented is that chars are *at least* 8 bits
in size.
scott@slp53.sl.home (Scott Lurndal): Nov 06 02:01PM

>> come to mind immediately.
 
>Does it even have a modern C++ compiler? Does anybody even know how to use
>such a thing?
 
1) Unknown, but unlikely. Does have a C compiler IIRC.
2) Yes, of course. They're still running production for many large
companies (including airline reservation systems).
David Brown <david.brown@hesbynett.no>: Nov 06 03:03PM +0100

On 06/11/18 14:33, Juha Nieminen wrote:
 
> It would only malfunction if CHAR_BIT is less than 8. The assumption
> I made in the solution I presented is that chars are *at least* 8 bits
> in size.
 
I hadn't actually read that bit of the thread!
 
CHAR_BIT is /always/ at least 8, so you are safe there.
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: Nov 06 01:31AM -0500

Thiago Adams wrote:
>> https://stackoverflow.com/questions/15773282/access-ident-information-in-an-executable
 
> I don't think it a good idea to increase the size to keep
> this information.
From my practice, I don't recall when that one string per source file created
any size issues (the overhead is usually less than 1-2%). Your mileage can vary,
of course. A good thing it gives you a certainty that a particular binary is
built from particular set of sources; without injecting a string to the binary,
this cannot be done (you might be able to inject something to debug sections,
then strip these off though; but this is not what #ident / #scsi do).
 
> pragma once span is to reuse the parsed header in more than
> one source file. It will take in account the macros for the
> first inclusion and after that it will not be expanded anymore.
 
Are you going to actually compile this file or just pre-process?.
 
If the latter, you probably don't need new pragmas; in fact, you don't even need
the pre-processing result's to be a valid C/C++ file. You could just have
something like
 
 
#ifdef WIN32
..\Scr\ConsoleWin.c
#elif defined(linux)
..\Scr\ConsoleLinux.c

No comments: