FPC feature request/suggestion lazarus / 64-FPC development ---------------------------------------------------------------------- 440bx · 2022-06-29 02:36 Hello, In Windows, it's becoming quite common for structures to include a size field which the O/S uses at runtime to determine which fields it can set.  It would be very nice if FPC supported a variant of "sizeof" where it could take a field name, i.e, sizeof(, ) yielding the size of the record up to and _including_ the field. There is a way of doing it but, it is very unclean because, it requires using the name of the field that _follows_ the field of interest which makes it completely unclear what the last field to be included is. Succinctly: a sizeof(, ) It's might be worth noting that the compiler already has the necessary information in its symbol tables to implement this compile time facility. Thank you for reading. ---------------------------------------------------------------------- marcov · 2022-06-29 07:41 You mean like https://gitlab.com/freepascal.org/fpc/source/-/issues/15416  ? Note that ptrint(@pstruct(nil).field) is a workaround. ---------------------------------------------------------------------- 440bx · 2022-06-29 08:34 Quote from: marcov on June 29, 2022, 09:41:59 amYou mean like https://gitlab.com/freepascal.org/fpc/source/-/issues/15416  ? That's the basic idea but, the offset of the field is _not_ the size of the record up to and including that field.  To obtain the size of the record, including the field, requires adding the size of the field to its offset. As the posters in the feature request you linked to mentioned, that nil pointer dereference is not elegant and has a number of shortcomings.  It's, as you stated, a workaround and one that is not really clear nor very desirable. The compiler has the offset of every record field in its symbol tables, it can easily return the offset of any field and the size of a record up to and including the field, what's missing is a simple and straightforward way of asking the compiler for that information. OffsetOf(, ) _and_ sizeof(, ) would be _very_ nice features to have.  In C, these capabilities are implemented with macros but, they cannot be implemented using FPC's macro facilities. ---------------------------------------------------------------------- alpine · 2022-06-29 09:31 Quote from: 440bx on June 29, 2022, 04:36:51 amHello, In Windows, it's becoming quite common for structures to include a size field which the O/S uses at runtime to determine which fields it can set.  It would be very nice if FPC supported a variant of "sizeof" where it could take a field name, i.e, sizeof(, ) yielding the size of the record up to and _including_ the field. *snip* Sure it will be nice, but for what is that needed for? I'm not getting it clearly from your first sentence. ---------------------------------------------------------------------- 440bx · 2022-06-29 10:21 Quote from: y.ivanov on June 29, 2022, 11:31:22 amSure it will be nice, but for what is that needed for? I'm not getting it clearly from your first sentence. There are quite a few cases when it would be extremely convenient to have those features.  The most common case is when a Windows structure has changed and Windows relies on the size to determine what to return (fill in).  If a program can use sizeof(, ) then fields added later don't affect how the code works.  IOW, the layout of the record can be updated without causing any potentially damaging side effects in existing code that uses that record. Another case, less common, there are some programs that need to determine offsets and fields sizes at runtime, e.g, debuggers.  Without, OffsetOf and/or sizeof(, ) writing the code is very laborious and tedious not to mention that maintaining the code becomes difficult. Another case is when translating C headers.  In C, using the macros that are already in the headers, it is straightforward to create (even generate) a program that lists all the records along with their fields, including the field offset and size.  Doing that in Delphi/FPC is laborious and tedious, thereby making the verification that the translation is correct also tedious and time consuming. OffsetOf(, ) and sizeof(, ) would _really_ make life _much_ simpler in a number of important cases. ---------------------------------------------------------------------- MarkMLl · 2022-06-29 10:42 Quote from: 440bx on June 29, 2022, 12:21:07 pmThe most common case is when a Windows structure has changed and Windows relies on the size to determine what to return (fill in).  If a program can use sizeof(, ) then fields added later don't affect how the code works.  IOW, the layout of the record can be updated without causing any potentially damaging side effects in existing code that uses that record. I think that I'd argue is that you should use a case statement, and only support fixed-size data structures (i.e. preceded by an API- version-specific length) where the particular API version has been tested. Otherwise, where the data structure is not fixed length (i.e. is preceded by a varying length field like a Pascal string) I don't see the problem. MarkMLl ---------------------------------------------------------------------- 440bx · 2022-06-29 11:21 Quote from: MarkMLl on June 29, 2022, 12:42:45 pmI think that I'd argue is that you should use a case statement, and only support fixed- size data structures It's not that simple.  Consider you have a library of API definitions, MS adds a few fields to some structure, you add them to your definitions to keep up to date.  Now the problem is this, if the code is using "sizeof()" then it will be using the new larger record size and the existing code may or may not work correctly with a larger structure, that's why limiting to a specific field is important.  Otherwise, those additional fields would force the programmer to review _every_ program that uses that record to ensure it is not affected by the new size. By making the record size specific to one field then older code can be updated as needed or when convenient instead of, at least in some cases, breaking. Also, when translating headers, the two things that really matter are the offsets of each field (particularly when some of them have specific alignment requirements) and the record size up to and including a particular field.  If memory serves, the MS common controls library is full of "variations" based on record sizes.  It's really inconvenient not having a simple, clear and straightforward way of determining field offsets and record sizes up to and including a field. Those missing features in FPC'/Delphi also make verifying that structures are translated correctly from C to Pascal very tedious and laborious. ---------------------------------------------------------------------- MarkMLl · 2022-06-29 11:30 Quote from: 440bx on June 29, 2022, 01:21:41 pmadditional fields would force the programmer to review _every_ program that uses that record to ensure it is not affected by the new size. That's right. What you should be asking for is some form of annotation, possibly related to Lazarus's TODO, which can be applied to anything declared to mimic a non-Pascal API or data structure. MarkMLl ---------------------------------------------------------------------- alpine · 2022-06-29 11:39 Quote from: 440bx on June 29, 2022, 12:21:07 pmQuote from: y.ivanov on June 29, 2022, 11:31:22 amSure it will be nice, but for what is that needed for? I'm not getting it clearly from your first sentence. There are quite a few cases when it would be extremely convenient to have those features.  The most common case is when a Windows structure has changed and Windows relies on the size to determine what to return (fill in).  If a program can use sizeof(, ) then fields added later don't affect how the code works.  IOW, the layout of the record can be updated without causing any potentially damaging side effects in existing code that uses that record. Do you mean something like: Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i typedef struct {  int field;  int field2; // added in v2 of the api  int field3; // added in v3 of the api} apistruct, *papistruct; void APIfunc( papistruct arg, size_t arglen ) // latest api{   arg->field = 1;  if( arglen > offsetof( apistruct, field2 ) )  // v2 of the api?  arg->field2 = 2;  if( arglen > offsetof( apistruct, field3 ) )  // v3 of the api?    arg->field3 = 3;} // ... and in the api calling application:// (presumably built when api was < v3 and apistruct was shorter) apistruct s;   APIfunc( &s, sizeof( apistruct ) ); // call the recent APIfunc() with older version of apistruct Or you mean something different? Because I'm not using the proposed sizeof( apistruct, field3 ) above. Quote from: 440bx on June 29, 2022, 12:21:07 pmAnother case, less common, there are some programs that need to determine offsets and fields sizes at runtime, e.g, debuggers.  Without, OffsetOf and/or sizeof(, ) writing the code is very laborious and tedious not to mention that maintaining the code becomes difficult. That will be impossible at runtime without some sort of introspection or linker/debugger symbol table. IMO that is not what you're asking for, i.e. compile-time sizeof(, ). Quote from: 440bx on June 29, 2022, 12:21:07 pmAnother case is when translating C headers.  In C, using the macros that are already in the headers, it is straightforward to create (even generate) a program that lists all the records along with their fields, including the field offset and size.  Doing that in Delphi/FPC is laborious and tedious, thereby making the verification that the translation is correct also tedious and time consuming. OffsetOf(, ) and sizeof(, ) would _really_ make life _much_ simpler in a number of important cases. I still don't get it. Why showing offsets and sizes of structs defined in C headers from FPC? Patching something? BTW one of the few cases I used offsetof() in C was when I wrote patching of configuration structures in a micro-controller NV memory where it can be written by single words but only erased in bulk. And what's wrong with offsetof(a, b) + sizeof(b) compared to sizeof(a, b)?