j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
175 stars 14 forks source link

Option to have interoperable types packed #256

Closed sblionel closed 2 years ago

sblionel commented 2 years ago

I was helping someone in the ifort forum where they wanted to declare a derived type for the BMP (bitmap) file header. This is a 14-byte structure with two misaligned 32-bit integers. The problem is that there is no standard Fortran way to declare this. A SEQUENCE type allows the compiler to insert padding but doesn't specify it - some compilers do by default, some don't. An interoperable type requires padding if the "companion C processor" would do so, and in the absence of #pragma pack, they generally would.

I would like to see an option for declaring an interoperable type that says "do what the C processor would do if #pragma pack were in effect". A possible syntax would be:

type, bind(C,PACK) :: mytype

Given my usual dislike of one-way options, I'd also want to see NOPACK as a choice.

klausler commented 2 years ago

Some target architectures signal bus errors on misaligned memory references; others don't (at least not on some types of references) but can suffer silent performance degradation. So supporting misaligned components in general would be hard to make portable. You'd have to worry about whether to allow them as actual arguments and pointer targets, too.

Possible alternative solution for this use case, assuming that it was trying to use unformatted I/O on BMP files: make unformatted I/O of sequence &/or interoperable types skip over padding; i.e., the on-disk data would be packed, but the in-core data would be aligned. Easy to do, and wouldn't affect "normal" programs a all.

Are there use cases for misaligned components other than serialization and deserialization? It seems like this BMP case could also be handled in portable Fortran pretty easily with TRANSFER to/from a byte array.

sblionel commented 2 years ago

There are numerous APIs I have seen with misaligned fields, and the C headers for them have #pragma pack. I agree, and in fact suggested to the user, that TRANSFER here would not be too annoying, but I can imagine other cases where it would be more complex. As I see it, this is an improvement to interoperability that is easy to explain and has minimal impact on the language.

klausler commented 2 years ago

Be advised, "#pragma pack" is not part of a C/C++ standard; neither is GCC's __attribute__((packed)).

Will there be restrictions on references to misaligned components? Pointers to them? Usage as actual arguments? This is a feature that will have some subtle implications, if you want misaligned components to be first-class variables. For example, passing a misaligned component as an actual argument associated with an dummy with the TARGET attribute requires additional semantics in the subclause that effectively limits the lifetime of validity of a pointer that's been aimed at the dummy argument, so as to allow for copy in/out.

(Unless you want to simply state that the program does anything but TRANSFER() and unformatted I/O with misaligned components at its own risk, which would be what "minimal impact" on Fortran would have to look like.)

sblionel commented 2 years ago

Thanks for that insight, @klausler . I am not conversant with the C standard and had thought that #pragma pack was standard. Now that I know it isn’t, I would not support this.

I don’t see the issues you do with misaligned components - Fortran programs deal with these all the time in other contexts.

klausler commented 2 years ago

Thanks for that insight, @klausler . I am not conversant with the C standard and had thought that #pragma pack was standard. Now that I know it isn’t, I would not support this.

I don’t see the issues you do with misaligned components - Fortran programs deal with these all the time in other contexts.

#pragma is standard, but the specific pragmas are not. #pragma pack is certainly a de facto standard. I think that you could define this feature in a usable way without needed to define it in terms of ISO C/C++ standards.