Strict aliasing rule (MISRA-C)



  • Hallo Leute,

    vll. ist von euch die MISRA-C rule ein begriff!? Aber unabhängig davon geht es um folgende Sache. In C99 und (MISRA-C) konform habe ich eine Datenstruktur (Geometrie) welche aus Segementen (Line, Arc) besteht.

    Ein Segment hätte ich mir so vorgestellt:

    
    #include <stdint.h>
    #include <string.h>
    
    struct Common
    {
        char type;
        uint16_t payload[3];
    } Common;
    
    struct Line 
    {
        char type;
        uint16_t P1;
        uint16_t P2;
        uint16_t res;
    } Line;
    
    struct Arc 
    {
        char type;
        uint16_t P1;
        uint16_t P2;
        uint16_t radi;
    } Arc;
    
    union Seg
    {
        struct Common common;
        struct Line line;
        struct Arc arc;
    } Seg;
    
    static union Seg segments[10];
    
    static struct Common geometry[10];
    
    int main()
    {
        /* opt: (A) union */
        segments[0].arc.P1 = 3;
        segments[1].line.P1 = 4;;
    
        /* opt: (B) copy */
        struct Line line;
        memcpy(&line, &geometry[0], sizeof(Common));
    
        /* opt: (C) type punning */
        struct Line* x = (void*)&geometry[0];
    }
    

    Nun welche Option "könnte" wäre denn MISRA-C konform? vermutlich nur B?

    Option C, is ne grauzone : https://forum.misra.org.uk/thread-1628.html

    C99 : 6.5.2.3 Strict aliasing rule https://www.dii.uchile.cl/~daespino/files/Iso_C_1999_definition.pdf Punkt 5 verwirrt noch etwas?

    Aber nichts desto trotz, hat jemand ne Idee wie ich sowas vll. ganz anderes darstellen könnte!?

    Danke euch



  • @SoIntMan
    Nur (A) ist MISRA-Konform, weil B+C Standardinkonform sind, weil sie UB sind. (Gut, C erst wirklich UB bei Dereferenzierung).
    C ist keine Grauzone, sondern klar geregelt - ist UB; nur du selbst ignorierst das, indem du den Zeiger castest und damit dem Compiler signalisierst, ich weiß es besser als du, was nicht der Fall ist.
    Die union ist Quark, sinnfrei und fehleranfällig. Ebenso Common.

    typedef struct
    {
      char type;
      uint16_t P1;
      uint16_t P2;
      uint16_t res;
    } Line_t, Arc_t;
    
    int main ()
    {
      Line_t lines[10] = { 0 };
      Arc_t arcs[10] = { 0 };
    
      arcs[1] = lines[2];
      lines[3] = arcs[5];		/* usw */
    
      memcpy (lines, arcs, 10 * sizeof *lines);
    }
    

    Hier ist alles standardkonform, und damit ohne UB.

    https://onlinegdb.com/PgEqGHJzV

    Bei struct Definitionen solltest du immer von größeren zu kleineren Elementen sortieren, also nie mit char anfangen, wegen der Paddingbytes.
    In Rust ist das anders, dort wird automatisch die Speicheranordnung der Elemente optimiert, es sei denn, du verbietest es explizit.


Anmelden zum Antworten