On 22/11/2019 19:35, Soviet_Mario wrote:
> Il 22/11/19 15:04, David Brown ha scritto:
>> On 22/11/2019 13:14, Soviet_Mario wrote:
>>> Il 22/11/19 12:23, David Brown ha scritto:
<snipping quite a bit to cut down on the size of the post>
> put is alas irregular verb : I meant its PAST form actually.
> I have abandoned the unsigned Bit_Field : 8 solution as soon as you (a
> lot of people) stated that u_int_8 MUST have exactly 8 bits.
>
> In that case either pragma is USELESS (and hence does not produce any
> reasonable effect, neither slowness), either is NECESSARY (and so the
> slowing effect is a unavoidable price that I MUST pay either)
A "pack" attribute is unlike to have any effect when you have only
uint8_t types in a struct or array. There is a hypothetical possibility
of it affecting padding or alignments on the struct as a whole, but that
will definitely not apply for any platform "normal" enough to support
QT. But have no positive or useful effects does not guarantee that you
will get no negative effects in terms of efficiency or what the compiler
allows for the code, and certainly you will still have the negative
effects of non-portable code and confusing source code.
>
>> "Packed" is /not/ a
>> "precaution", nor is using a struct with a bitfield instead of uint8_t.
>
> the second part has been abandoned early
OK.
>
>> If you don't know what you are doing
>
> I'm rather weak in higher level C++ constructs, and I know that, but not
> particularly so in low level (some couple of tens of years ago I used to
> stuff C code with inline "asm" statements or even __emit() calls).
>
>> , fine - if I understand you
>> correctly, you are experienced with gambas
>
> no, I am rather new to gambas actually.
> I was used to VB (Visual Studio, but not even recently). Going to Gambas
> has been actually a pain (not saying it is bad, absolutely not : it's me
> that knows much less than .net framework). On QT I am even more newby.
>
>> programming but new to C++.
>
> well, I am more of outdated than new, I had used C++ (and C) a lot in
> 1995-2000 roughly, then less and less afterwards.
> But strangely enough, I find it more easy to think in C++ terms when I
> met problems in basic.
OK.
>
>> So /ask/ (and please read the answers). Don't guess, or grab the first
>> thing that you find from a google search.
>
> but I DID follow the answers :)
I saw a lot of posts indicating that you either didn't read the answers,
didn't understand them, didn't agree with them, or at least did not rate
them as reliable sources of information. There have been so many posts
in this thread that it is hard to have an overview, but I believe you
made several "I'm keeping pragma pack as a precaution" posts after
having been told how it is worse than useless. But maybe I have a false
impression here, based on the order of reading posts or details of what
were written.
>
>> And when the more experienced
>> people in a group like this all say "don't use packed" and "use
>> uint8_t",
>
> I didn't read or desume the two things should be mutually exclusive.
I can see how that might not have been clear at the start.
>
> Anyway, there are three scenarios
>
> 1) added pragma (to the four u_int_8 members in a struct) is USELESS, as
> the struct was just packed natively (and hence does not produce any
> reasonable effect, neither slowness),
Yes, it is useless here.
> either
> 2) is NECESSARY, as the struct would not have been natively packed
> otherwise (and so the slowing effect is a unavoidable price that I MUST
> pay either)
When you have understood what "packed" does, and how compilers handle
structs, you will realise that this will not be the case. (Any
compiler/target combinations sufficiently odd that uint8_t structs are
not tightly packed anyway, are unlikely to support "pragma pack", almost
guaranteed not to support QT, and are definitely not platforms you will
be using anyway.)
> either
> 3) it is NOT SUFFICIENT (in this case, luckily unlikely, nothing would
> have worked fine at all)
Correct.
But you have missed the fact that there are potential disadvantages in
using "pack" even when it offers no advantages.
>
> as for ALIGNMENT problem, I should not meet any I guess.
> The packed (natively or forcefully) struct is 32 bit wide, so allocating
> an array should allow nice addressing of any item even on a 64 bit OS
> And no item would cross critical addressing boundary
The struct will be 32 bit in size, but the alignment will be one byte.
Whether you consider that an advantage or disadvantage compared to four
byte alignment depends on how it will be used.
>
>
>> then that is what you should do. Ask /why/, and try to learn
>> - and once you do understand "pack", when it can be useful, when it is
>> useless, when it is worse than useless,
>
> If you have some further patience, tell me if the 3 scenarios fit the
> present situation (not a more general one, but just this)
Hopefully my reply above covers this.
>
>> what it does, and what it costs
>> - /then/ you can decide that because you know the full situation better
>> than we do, you still want to use it against general advice.
>
> I had given all details sufficient : the data layout is what I said, so
> no obscure aspects
>
>>
>> "Packed" is not a precaution -
>
> I call it a precaution as it reduces the chances of a non packed data
> layout.
It does not do that - the chances of the uint8_t data not being packed
are 0, and "packed" does not reduce those chances. Therefore it is not
a "precaution".
> I was not saying it would be successful necessarily in every
> scenario (even sizes sequence is relevant, and I know this, but my
> members were all 1 byte long)
>
>> it is a last choice solution when you
>> have nothing better and know you can't write the code as well without
>> it. (That might mean you can't write the code as quickly or clearly
>> without it, which is fair enough - /if/ you are sure it is necessary.)
>
> let's say it explicitely
>
> if I have
> union
> {
> struct
> {
> u_int_8 Red, Green, Blue, Alpha;
> };
> u_int_32 AllChannels;
> };
>
> without PRAGMA, do I have any explicit or implicit warranty that my
> union be 32 bit long ? If so, PRAGMA is useless. If not, it seems it
> might be useful.
If you keep using non-standard types, then we can't be entirely sure. I
know what the standard types "uint8_t" and "uint32_t" are, but I have no
definition for "u_int_8" and "u_int_32". I /assume/ they are defined
like the standard types, but you might have made a mistake. I strongly
recommend you don't use home-made types like this when there are
perfectly good standard types available.
The C and C++ standards give implementations a lot of freedom about
packing, padding and alignments in structs and unions. But practical
implementations do not do anything weird unless they have good reason
for it. When you are talking about mainframes, supercomputers, DSPs, or
particularly odd niche processors, you need to be careful and check the
details. For ordinary computers, and code that would never be used on
anything else, there is no problem. (For a guide, anything targetting a
POSIX or Windows system, or any embedded system supported by gcc or
clang, there will be no problems.) On such "ordinary" targets, all
basic types are 8-bit, 16-bit, 32-bit, 64-bit or 128-bit, and the
alignment of those types is at most equal to their size. (It can be
smaller, however, if the "bitness" of the cpu is smaller than that
size.) No padding is added except to make sure each struct member is
aligned, and that the struct itself is aligned by the biggest alignment
of any member.
> what damages could PRAGMA PACK produce ?
I've told you already.
> If the union would be just packed natively, I guess none.
No.
It /might/ be the case that the only disadvantages of "pragma pack" are
lack of portability to other tools on the same or similar platforms, and
confusion for the reader as to why you have added this useless pragma.
But it is also possible that it will restrict what you can do with the
struct (like taking the address of the members), it can lead to errors
that are not diagnosed (like letting you take the address of the
members, but those addresses not being aligned and this leading to
subtle problems when the compiler assumes they /are/ aligned), it can
lead to inefficiencies (like compilers generating byte-by-byte access to
larger fields on some targets) or compilers being pessimistic about
optimisations.
> If it wasn't, at best it would pack it (and maybe slow it, but this is
> irrelevant, I need precise disk layout).
If the union was not packed natively, you'd be working on a very odd
system and "pragma pack" would not apply anyway.
> At worsk it would be
> insufficient to actually pack it, so my problem is unsolved.
> In this last worst case, are there any other means of getting the thing
> to work ?
> What are them ?
>
If you are dealing with a system where you can't be sure your simple
arrays and structs are packed sensibly (at most padded for "natural"
alignment), you can't handle it this way anyway - you are going to have
to write code that manually unpacks the raw stream of byte data.
<snip>
>> And if your file format contains non-aligned members,
>
> why making general guess when I reported precisely the layout ?
> I said :
> 16 bit (width) - 16 bit (height) - N x 32 bit (R,G,B,alpha)
> where N = width x height = number of "pixels"
That does not tell us anything about alignment. Are your fields
properly aligned or not?
>
> every pixel is multiple of 32 address on file (but this seems irrelevant
> to me).
I presume you mean multiple of 32 bits, i.e., 4 bytes. And yes, this is
/highly/ relevant. It means your data is well aligned, and you can use
a union with a uint32_t for your pixels (if you want). Are you also
sure that your 16-bit values (height and width) are 16-bit aligned? As
long as all your elements are naturally aligned, then the struct is
properly aligned and you can use a plain, simple struct with no "packed"
complications.
This is /critical/ to being able to support your structure simply,
cleanly, efficiently and portably. That is why I have repeatedly asked
you if your format is properly aligned.
> In the ram layout,
> the BMP descriptor has width and height as "local" members, and a
> pointer to an array of struct aligned in memory by the NEW [] operator
> who is aware of alignment requirements.
>
> Where are the possible problems ?
> What problems are affected by a pragma pack directive ?
>
>
>> then the simplest
>> and easiest way to improve and simplify the code, and improve the speed
>> of several parts, is to fix the file format.
>
> that point is unmodificable. I strictly need full color and no
> compression. The alpha channel is maybe a bit overkill (255 level of
> transparency is more than needed ... but taking less is useless or
> impossible, and 1 byte is natural for the otherwise 3,sth bytes long
> struct)
I haven't suggested using smaller types for your data - I assume that
these are appropriate types.
>
>> Make sure the members are
>> aligned (add explicit dummy members if necessary)
>
> since when reading/writing files suffer from this ? Files are BYTE
> oriented internally (and the OS does caching independently and
> transparently, basing on disk cluster sizes but this is not sth I should
> care of)
It does not affect the file reading and writing - it affects the struct
in memory that is accessed by the code. C and C++ only define access to
correctly aligned objects and subobjects. Access to unaligned data is
implementation dependent, may require extra extensions (like pragma
pack), may be subject to various restrictions, may be inefficient
(either extra code, or inefficiencies in the cpu processing), and may
cause problems if the data is used with third-party libraries or code.
That is a good plan. When you do that, you avoid any need for "pack"
extensions.
It appears that you have designed a /sensible/ file format. It is
/simple/, but certainly not "stupid". It has taken a while to get you
to give enough details to establish this, but it seems to have been a
sensible format all along.
What you have got wrong is your determination to distrust your own
sensible decisions in the file layout and add worse than useless extra
"pack" junk. Forget "pack" - forget you ever heard of it. It is not
part of the C++ language, it is rarely useful, and it is certainly not
useful here. Just use your file format in the clear, sensible layout
you have designed.
>
>>
>> As for asking for help here, you are getting the help you need even if
>> it is not exactly what you asked for.
>
> not a problem, every advice is appreciated
>
>> It's as though you said "I need a
>> new toothbrush. Can you tell me how to get to the toy shop?" It is
>> conceivable that a toy shop might have toothbrushes, but it is very
>> unlikely to be a good choice. Would you not rather have people say "You
>> don't want to go to a toy shop. You want to go to a chemist - this is
>> how you get there" ?
>>
>>>
>>>> read or write it from the disk. You haven't compared the time the
>>>> processing takes for a "packed" struct to how it would run with an
>>>> unpacked struct.
>>>
>>> forgive me : how to read an all packed file in an array of UNpacked data
>>> of different layout, in a single read operation ? I can't figure out
>>> this
>>>
>>
>> First, you take a step back. You look to see if the packed file really
>> is "packed",
>
> it is, as both Gambas supports BYTE format (And sizeof()) and
> BYTE-oriented streams. No overspace is generated. Then I have to worry
> about the C++ back end, to comply with this fact.
My knowledge of Gambas is very limited, but according to the
documentation I found its structs are /not/ packed:
<
http://gambaswiki.org/wiki/lang/structdecl>
Padding /is/ generated - if needed to get the natural alignment of the
fields. You can be entirely confident that on any platform supported by
Gambas, the padding, alignment and layout of a Gambas struct and a C++
struct will be the same.
>
> I think the designer of Gambas relies very strongly upon C libraries and
> mind-shape, apart from strings (where he had to welcome BASIC users who
> want strings the basic way).
Of course. And while the details of C struct layouts is implementation
dependent, it is invariably the simplest and most obvious but efficient
layout for the target.
>
>> in the sense of having unaligned data that would have
>> padding in a normal struct. I have seen no answer to this (unless it is
>> later in this post), despite asking this /crucial/ question.
>
> the files are packed.
The information you have given so far in this post suggests they are
properly aligned. They are without padding, but that is because of the
field sizes used and their arrangement, not because you have
specifically asked for non-standard packing.
>
>>
>> If the format is already good, you are done. One memcpy, or read from
>> the file directly to a suitable buffer, or memmap to the file directly
>> (no reading or writing needed).
>
> memmap is a problem in that I don't know how exactly works and whether
> or not I'll be able to interoperate with memory files opened in gambas
>
> I am also considering to use some memory files supported directly by the
> OS (here on linux files created on /shm virtual folder are designed for
> such FAST temporaries to be shared, but with portable stream syntax).
> Using /shm would imply no specialized load/store code, just the normal
> file access => delegating the ram usage to the OS.
If your files are in a ram file system (/shm, tmpfs, etc.) then memmap
would not be faster anyway.
>
>>
>> If the format is bad, the next step is to consider changing the format.
>
> just observation.
> So, the format is wrong ?
/You/ tell /me/. Only /you/ know the full format. But from what you
have said here, the format is probably fine.
>
>> This would be good for all parts of the system. When the format is
>> changed, you are done. Again, I have had no answer to whether this is
>> possible.
>>
>> If the format is bad, and cannot be fixed, then you have to write reader
>> and writer functions that unpack and pack the data into the right
>> formats. Reader and writer functions are common for all sorts of
>
> well, I'd be considering these for small size, complex structured input,
> not for a 4-12 MB size of simple pixels. It would be a blood bathe
You are basing that on speculation with no evidence.
I am not at all saying that it is a bad idea to use a direct mapping
from file format to struct - indeed, it is a sensible idea whenever you
can define the format.
As far as I understand your project, you are using Gambas for a gui but
for some kind of image processing, you are saving the pictures from
Gambas as files, then starting an external C++ program that reads these
files, processes them in some way, and saves them again, and then the
Gambas program will read them in again.
I have no idea if this is a good method - either from the viewpoint of
development ease, or run-time efficiency. I can think of many
alternative ways to structure this task, which may or may not be better
- without knowing details of the task, or why you might prefer a
particular setup.
But it does seem to me that you are making your decisions based on gut
feeling rather than research or measurement. That does not mean your
decisions are wrong, but it might mean you should not be so confident in
them.
It sounds like it is probably fine - but as I have said before, you
haven't given all the important details clearly enough.
I want you to understand what is important when making such structures -
that everything is aligned properly (the best being "natural"
alignment), and I strongly recommend adding any padding manually as
unused "padding" fields. I want you to understand /why/ this is
important. And once you understand that, you will realise that "pragma
pack" and similar extensions are useless here and not only are you able
to avoid them, but you /should/ avoid them.
No, it is not. Not remotely. It would be a sad state for C and C++ if
they required compiler-specific extensions to deal with data from
external sources.
I think perhaps you are mixing up the concepts of "a structure where the
fields are adjacent with no padding" and "uses pragma packed". I am
recommending using structs fit the former, without ever using the later.
Or perhaps you think compilers add random padding and re-arrange structs
in odd and unpredictable ways. The details here are usually specified
by the platform's ABI, precisely so that programs can exchange data
safely (by files, pipes, streams, shared memory, shared libraries, etc.).
> And also the caller expects to get the transformed data back in the same
> packed form.
>
>> means totally pointless complications, inefficiencies, and non-portable
>> code.
>
> nope, I have constraints to fullfil. Maybe inefficient, maybe non
> portable (who cares ?), but surely not pointless, as otherwise data
> exchange would not work at all
"pragma pack" is pointless here.