Discussion:
C89 "bug"
Add Reply
Thiago Adams
2024-12-13 12:15:58 UTC
Reply
Permalink
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.
Michael S
2024-12-13 12:56:39 UTC
Reply
Permalink
On Fri, 13 Dec 2024 09:15:58 -0300
Post by Thiago Adams
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;
};
Thiago Adams
2024-12-13 13:26:06 UTC
Reply
Permalink
Post by Michael S
On Fri, 13 Dec 2024 09:15:58 -0300
Post by Thiago Adams
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;
};
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 };
Kaz Kylheku
2024-12-13 15:01:13 UTC
Reply
Permalink
Post by Thiago Adams
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: @***@mstdn.ca
Thiago Adams
2024-12-13 15:41:04 UTC
Reply
Permalink
Post by Kaz Kylheku
Post by Thiago Adams
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;
}
bart
2024-12-13 18:39:26 UTC
Reply
Permalink
Post by Thiago Adams
Post by Kaz Kylheku
Post by Thiago Adams
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.
Thiago Adams
2024-12-13 18:50:44 UTC
Reply
Permalink
Post by bart
Post by Thiago Adams
Post by Kaz Kylheku
Post by Thiago Adams
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.
Yes..
Keith Thompson
2024-12-13 18:15:32 UTC
Reply
Permalink
Post by Thiago Adams
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.

Of course the best solution is to use C99 or later, unless there's
some reason you can't.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Thiago Adams
2024-12-13 18:24:34 UTC
Reply
Permalink
Post by Keith Thompson
Post by Thiago Adams
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 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.
David Brown
2024-12-13 18:51:43 UTC
Reply
Permalink
Post by Thiago Adams
Post by Thiago Adams
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 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.
Thiago Adams
2024-12-13 18:59:42 UTC
Reply
Permalink
Post by David Brown
Post by Thiago Adams
Post by Thiago Adams
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 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.)
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.
Interesting!
Dependency on sizes is not a problem because the generated code is
intended to be used in a pipeline and discarded after feeding a C compiler.
Your suggestion is basically to have a struct of "words" that have the
same size of the structs. Then convert 1.2 (double) to two words.
It makes sense!
Thiago Adams
2024-12-13 19:07:28 UTC
Reply
Permalink
Post by Thiago Adams
Post by David Brown
Post by Thiago Adams
Post by Thiago Adams
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 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.)
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.
Interesting!
Dependency on sizes is not a problem because the generated code is
intended to be used in a pipeline and discarded after feeding a C compiler.
Your suggestion is basically to have a struct of "words" that have the
same size of the structs. Then convert 1.2 (double) to two words.
It makes sense!
https://godbolt.org/z/cKb4j35W8

#include <stdio.h>

union U {
unsigned int _[2];
int i;
double d;
};

union U u1 = {1, 0}; /*1.2*/
union U u2 = {858993459, 1072902963}; /*1.2*/
int main(){
printf("u1.i = %d\n", u1.i);
printf("u2.d = %f\n", u2.d);
}
bart
2024-12-14 00:04:09 UTC
Reply
Permalink
Post by David Brown
Post by Thiago Adams
Post by Thiago Adams
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 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.)
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.
David Brown
2024-12-15 09:56:27 UTC
Reply
Permalink
Post by bart
Post by David Brown
Post by Thiago Adams
Post by Thiago Adams
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 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.)
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!
Post by bart
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.
Keith Thompson
2024-12-13 20:29:13 UTC
Reply
Permalink
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
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 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().

Initializing u to some known invalid value, if there is one, could
help in detecting the error of forgetting to set a valid value.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Scott Lurndal
2024-12-13 20:47:06 UTC
Reply
Permalink
Post by Keith Thompson
Post by Thiago Adams
Post by Keith Thompson
Post by Thiago Adams
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 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.
Waldek Hebisch
2024-12-14 05:46:20 UTC
Reply
Permalink
Post by Thiago Adams
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
Keith Thompson
2024-12-14 06:02:22 UTC
Reply
Permalink
Post by Thiago Adams
Post by Thiago Adams
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 {
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.
It's not. With "-std=c90 -pedantic", gcc (correctly) warns:

ISO C forbids casts to union type [-Wpedantic]

The specific constraint in the C90 standard is:

Unless the type name specifies void type, the type name shall
specify qualified or unqualified scalar type and the operand
shall have scalar type.

(Later editions have similar wording.)
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+***@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
Loading...