• Re: C89 "bug"

    From Michael S@21:1/5 to Thiago Adams on Fri Dec 13 14:56:39 2024
    On Fri, 13 Dec 2024 09:15:58 -0300
    Thiago Adams <thiago.adams@gmail.com> wrote:

    Does anyone knows how can I convert this code (external declaration)
    to C89?

    union U {
    int i;
    double d;
    };

    union U u = {.d=1.2};

    The problem is that in C89 only the first member of the union is
    initialized.


    union U {
    double d;
    int i;
    };

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Thiago Adams on Fri Dec 13 15:01:13 2024
    On 2024-12-13, Thiago Adams <thiago.adams@gmail.com> wrote:
    unfortunately, this solution does not work if we have two objects.

    union U {
    double d;
    int i;
    };

    union U u1 = { .d=2.2 };
    union U u2 = { .i=1 };

    Idea: have several declarations of the union in different translation
    units.

    /* translation unit for u1 */
    union U {
    double d;
    int i;
    };
    extern union U u1 = { 2.2 };

    /* translation unit for u2 */
    union U {
    int i;
    double d;
    };
    extern union U u2 = { 1 };

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to Thiago Adams on Fri Dec 13 18:39:26 2024
    On 13/12/2024 15:41, Thiago Adams wrote:
    Em 12/13/2024 12:01 PM, Kaz Kylheku escreveu:
    On 2024-12-13, Thiago Adams <thiago.adams@gmail.com> wrote:
    unfortunately, this solution does not work if we have two objects.

    union U {
             double d;
             int i;
       };

    union U u1 = { .d=2.2 };
    union U u2 = { .i=1   };

    Idea: have several declarations of the union in different translation
    units.

    /* translation unit for u1 */
    union U {
       double d;
       int i;
    };
    extern union U u1 = { 2.2 };

    /* translation unit for u2 */
    union U {
       int i;
       double d;
    };
    extern union U u2 = { 1 };


    another solution could be call a function that initializes before main.

    extern union U u1;

    void before_main()
    {
      u1.d = 1.2;
    }



    I assume the initialisation is at file-scope.

    Then your suggestion could work, if you can arrange for it to be called.

    But I think that will be a problem: this can occur in some arbitrary
    module compiled at a different time from the one containing the
    program's main(): either earlier, or later.

    How will the compiler know which function(s) needs to be called from
    main(), when it translated the module containing main?

    I can think of an approach, but it's not simple, and may be over-kill if
    this is something that is infrequently encountered.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to Thiago Adams on Fri Dec 13 19:51:43 2024
    On 13/12/2024 19:24, Thiago Adams wrote:
    Em 12/13/2024 3:15 PM, Keith Thompson escreveu:
    Thiago Adams <thiago.adams@gmail.com> writes:
    Does anyone knows how can I convert this code (external declaration)
    to C89?

    union U {
         int i;
         double d;
    };

    union U  u = {.d=1.2};

    The problem is that in C89 only the first member of the union is
    initialized.

    The obvious solution is:
         union U u;
         u.d = 1.2;
    But that works only if u has automatic storage duration.

    You could also define a function that takes a double argument and
    returns a union U result.

    Like this?
    union U {
        int i;
        double d;
    };
    union U f(){ union U u; u.d = 1.2; return u;}
    union U u = f();

    The problem is that f() is not a constant expression for external declarations.


    Can you use gcc extensions here, or are you looking for strict C89
    compliance?

    (To me, the "bug" is using C89 in the first place, but you have your
    reasons for that.)

    Another option if you are generating code is to make your union :

    union U {
    struct { unsigned int lo; unsigned int hi; } raw;
    int i;
    double d;
    };

    and always initialise it with the underlying representation for the
    values and types that you want. (I believe you are generating the code,
    so that should be practical even for floating point data.)

    However, that puts a dependency on the endianness and size of types.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Keith Thompson on Fri Dec 13 20:47:06 2024
    Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
    Thiago Adams <thiago.adams@gmail.com> writes:
    Em 12/13/2024 3:15 PM, Keith Thompson escreveu:
    Thiago Adams <thiago.adams@gmail.com> writes:
    Does anyone knows how can I convert this code (external declaration)
    to C89?

    union U {
    int i;
    double d;
    };

    union U u = {.d=1.2};

    The problem is that in C89 only the first member of the union is
    initialized.
    The obvious solution is:
    union U u;
    u.d = 1.2;
    But that works only if u has automatic storage duration.
    You could also define a function that takes a double argument and
    returns a union U result.

    Like this?
    union U {
    int i;
    double d;
    };
    union U f(){ union U u; u.d = 1.2; return u;}
    union U u = f();

    The problem is that f() is not a constant expression for external
    declarations.

    Yes, that's a good point. Even in modern C, the initializer for
    a static object has to be constant.

    A function probably doesn't have much advantage over assigning
    the member directly. Either way, that code has to be executed in
    some function.

    If this is in human-written code, then there's the risk of forgetting
    to invoke the initialization code (or invoking it at the wrong time),
    since it can't be directly associated with the object definition.
    That's why the C99 and later solution is IMHO much better.)
    But if this is generated code, you can just generate code to do
    the assignment, perhaps in main().

    GCC does offer __attribute__((constructor)) to designate a
    function that should execute before main as an extension.

    There are also methods using external symbols, linker scripts and binary
    blobs to initialize data at build time. None of these,
    of course are defined as part of "Standard C" whether 89 or 23.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From bart@21:1/5 to David Brown on Sat Dec 14 00:04:09 2024
    On 13/12/2024 18:51, David Brown wrote:
    On 13/12/2024 19:24, Thiago Adams wrote:
    Em 12/13/2024 3:15 PM, Keith Thompson escreveu:
    Thiago Adams <thiago.adams@gmail.com> writes:
    Does anyone knows how can I convert this code (external declaration)
    to C89?

    union U {
         int i;
         double d;
    };

    union U  u = {.d=1.2};

    The problem is that in C89 only the first member of the union is
    initialized.

    The obvious solution is:
         union U u;
         u.d = 1.2;
    But that works only if u has automatic storage duration.

    You could also define a function that takes a double argument and
    returns a union U result.

    Like this?
    union U {
         int i;
         double d;
    };
    union U f(){ union U u; u.d = 1.2; return u;}
    union U u = f();

    The problem is that f() is not a constant expression for external
    declarations.


    Can you use gcc extensions here, or are you looking for strict C89 compliance?

    (To me, the "bug" is using C89 in the first place, but you have your
    reasons for that.)

    Another option if you are generating code is to make your union :

    union U {
        struct { unsigned int lo; unsigned int hi; } raw;
        int i;
        double d;
    };

    and always initialise it with the underlying representation for the
    values and types that you want.  (I believe you are generating the code,
    so that should be practical even for floating point data.)

    However, that puts a dependency on the endianness and size of types.


    It gets a bit tricky also if it includes initialised 64-bit pointers
    (you can't split those). And also if the fields are deliberately
    misaligned (so using an intptr_t array won't be enough).

    There are other issues as well, but this depends on how far the OP is
    going. For example, when the definition for the union is inside an
    imported third party header, so only the initialisation is inside the
    code being translated.

    But maybe those external types will be recreated so can be augmented.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Waldek Hebisch@21:1/5 to Thiago Adams on Sat Dec 14 05:46:20 2024
    Thiago Adams <thiago.adams@gmail.com> wrote:
    Does anyone knows how can I convert this code (external declaration) to C89?

    union U {
    int i;
    double d;
    };

    union U u = {.d=1.2};

    The problem is that in C89 only the first member of the union is
    initialized.

    The following:

    union U {
    int i;
    double d;
    };

    union U u = (union U)(1.2);

    is accepted by 'gcc -S -std=c90'. I leave to others to check
    if this is valid C89.

    --
    Waldek Hebisch

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Brown@21:1/5 to bart on Sun Dec 15 10:56:27 2024
    On 14/12/2024 01:04, bart wrote:
    On 13/12/2024 18:51, David Brown wrote:
    On 13/12/2024 19:24, Thiago Adams wrote:
    Em 12/13/2024 3:15 PM, Keith Thompson escreveu:
    Thiago Adams <thiago.adams@gmail.com> writes:
    Does anyone knows how can I convert this code (external
    declaration) to C89?

    union U {
         int i;
         double d;
    };

    union U  u = {.d=1.2};

    The problem is that in C89 only the first member of the union is
    initialized.

    The obvious solution is:
         union U u;
         u.d = 1.2;
    But that works only if u has automatic storage duration.

    You could also define a function that takes a double argument and
    returns a union U result.

    Like this?
    union U {
         int i;
         double d;
    };
    union U f(){ union U u; u.d = 1.2; return u;}
    union U u = f();

    The problem is that f() is not a constant expression for external
    declarations.


    Can you use gcc extensions here, or are you looking for strict C89
    compliance?

    (To me, the "bug" is using C89 in the first place, but you have your
    reasons for that.)

    Another option if you are generating code is to make your union :

    union U {
         struct { unsigned int lo; unsigned int hi; } raw;
         int i;
         double d;
    };

    and always initialise it with the underlying representation for the
    values and types that you want.  (I believe you are generating the
    code, so that should be practical even for floating point data.)

    However, that puts a dependency on the endianness and size of types.


    It gets a bit tricky also if it includes initialised 64-bit pointers
    (you can't split those). And also if the fields are deliberately
    misaligned (so using an intptr_t array won't be enough).


    Those are good points. Perhaps one size does not fit all here, and the
    OP might want "raw" to be an appropriately sized "unsigned char" array
    for most cases, and a "void *" pointer to handle pointers. However, I
    can't think of any standard C89 way to handle the situation where you
    have a platform with pointers bigger than "unsigned long", if he needs
    to target such systems.

    AFAIUI he is dealing only with standard C - thus there is no way to make unaligned fields, so that problem can be ignored!


    There are other issues as well, but this depends on how far the OP is
    going. For example, when the definition for the union is inside an
    imported third party header, so only the initialisation is inside the
    code being translated.

    But maybe those external types will be recreated so can be augmented.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)