Skip to content

Potential portability issues with Fmi2Status datatype representation #1051

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
clegaard opened this issue Jun 8, 2020 · 3 comments
Closed

Comments

@clegaard
Copy link

clegaard commented Jun 8, 2020

I have been toying around with implementing FMUs in Rust. Unlike many of c types, rust types must have a fixed size. I have since become aware that FMI3 is going to use the fixed-size defined by C99, which is a very nice improvement.

One thing that may still be problematic is the use of enumerations as arguments and return types.
After doing some research online and looking up the C99 standard, it seems that while enumerations are typically represented using 4 bytes, however, it would be legal for the compiler to represent Fmi2Status as a char, since it can represent all its enumerated values.

I have attached the relevant section of C99 below:
C_enums.pdf
https://stackoverflow.com/questions/366017/what-is-the-size-of-an-enum-in-c

I ran some experiments on GCC and Clang to see how the enum is being represented on different compilers. The code is based on https://stackoverflow.com/questions/20979565/how-can-i-print-the-result-of-sizeof-at-compile-time-in-c

#include "stdio.h"

/* Type definitions */
typedef enum
{
    fmi2OK,
    fmi2Warning,
    fmi2Discard,
    fmi2Error,
    fmi2Fatal,
    fmi2Pending
} fmi2Status;

char (*__kaboom)[sizeof(fmi2Status)] = 1;

int main()
{
    printf("size of enum is %d", sizeof(fmi2Status));
}

Compiling with gcc and clang on linux it seems the enum is 4 bytes.

clegaard@ubuntu:~/Desktop/enum_test$ gcc main.c
main.c:20:40: warning: initialization of ‘char (*)[4]’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
   20 | char (*__kaboom)[sizeof(fmi2Status)] = 1;
      |                                        ^

All compilers on my host machine and VM used 4 bytes to represent the type. I seen claims that STM compilers may use the shortest possible type to represent the enum, but I have been unable to reproduce. However, using the fshort-enums flag resulted in the enum being represented using a single byte.

clegaard@ubuntu:~/Desktop/enum_test$ gcc main.c -fshort-enums
main.c:20:40: warning: initialization of ‘char (*)[1]’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
   20 | char (*__kaboom)[sizeof(fmi2Status)] = 1;
      | 

In general, it seems that most of the time the enum will be represented as an int, but it is not guaranteed by C99. A solution to this could be to return an int32_t or similar that is able to represent all the enumerated values. This issue may be of value illicitonion/num_enum#21

@pmai
Copy link
Collaborator

pmai commented Jun 8, 2020

While of course C is a broken language, and C enums doubly so, this is only a theoretical problem, as you found out, in that any sane platform ABI will prescribe the size of enum types, otherwise all kinds of interoperability fly out of the window.

This is similar to the problem of padding in structs, where C99 more or less gives implementations leeway to add padding in all kinds of amounts and places, but ABI rules will tighten this down, in order to have any kind of binary portability.

Sure you can force a compiler to deviate from the ABI/sane defaults, but well, you get to keep both pieces, as they say...

Switching to an int type will loose all kinds of error checking/IDE completion support for the benefit of a theoretical problem (especially for return types, which will magically degrade to int anyway on sane ABIs for other unrelated reasons), which is a trade-off I would not like to take (see e.g. KhronosGroup/Vulkan-Docs#124 for a similar decision by the Vulkan people).

BTW for this reason sane foreign language interfaces of languages that must interface with C will take the ABI sizes into account, or let you manually specify them.

PS: Would I wish that broken languages and OSes die out? Sure, but that would leave none of the current crop standing, which would make for a bit of a barren field...

@andreas-junghanns
Copy link
Contributor

After this lengthy explanation: Can we close this issue, please?

@clegaard
Copy link
Author

clegaard commented Jun 9, 2020

Thank you @pmai for the answer. It seems this is more of a theoretical issue and something you would only have to explicitly deal with in cases where the FMU is not compiled in C.

@clegaard clegaard closed this as completed Jun 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants