osd7@homxa.UUCP (Orlando Sotomayor-Diaz) (01/11/85)
ANSI Draft of Proposed C Language Std. Mail your replies to the author(s) below or to cbosgd!std-c. Cbosgd is reachable via most of the USENET nodes, including ihnp4, ucbvax, decvax, hou3c.... Administrivia should be mailed to cbosgd!std-c-request. ARPA -> mail to cbosgd!std-c@BERKELEY.ARPA (+++ NOT TO INFO-C +++) **************** mod.std.c Vol. 2 No. 8 1/11/85 ******************* Today's Topics: On Decot's union initialization scheme; another method (1) ---------------------------------------------------------------------- Date: Thu, 10 Jan 85 15:45:50 est From: cbosgd!watmath!kpmartin (Kevin Martin) Subject: Union initialization; a better method In the following, 'you' refers to Dave Decot (hpdsa!decot). He writes: >Here goes a proposal you might have heard before. Please let me know if >there are any flaws in it. So far, nobody has been able to shoot it down. > >If the data used to initialize the union is appropriately cast, and that >data type is a valid member of the union, then there is no ambiguity nor >problem; the union will hold the value by definition, and the data will >be appropriately cast. No one can shoot it down, because it is probably sufficient to solve the problem. That doesn't make it a good solution. The problem with this method is that it lacks the ability to make the code self-documenting. Reading the code sample you give, all I can tell is that (for cell[1]), you are initializing one of the (char *)'s in the union to a pointer to "abc". It doesn't tell me *directly* which element you are initializing. For similar reasons, it is error-prone, due to C's implicit type conversions (e.g. if you neglected to declare (or mis-declared) the cv_char element, or mis-cast the value, call[0] would not receive the initialization you expected). In addition it causes an explicit cast to behave differently from an implicit type conversion to the same type, that is, this would be the only place in C where (type) (expr) would be different from (expr) /* implicitly cast into (type) */ As I said above, it works, but there are better solutions. Given that a syntactic change is required (you requires one to allow casting of aggregates when initializing a union of two structs whose elements are similarly typed), here is an alternative, which solves the problems I have voiced: Allow the initializer to be preceded by "element_name =" to name a specific element. If no element is named, the first element is initialized. The initializers are checked for type compatibility, just as they currently are for non-union initializers. For reference, here is your example again: (correcting a typo, cv_char_p should have read cv_char_a in one place) > #define UNKNOWN 00 > #define CHAR 01 > #define CHAR_P 02 > #define CHAR_A 03 > #define SHORT 04 > #define LONG 05 > #define FLOAT 06 > #define DOUBLE 07 > #define SHORT_A 010 > > struct { /* I know it doesn't have a name */ > int CellType; /* holds one of the above defines */ > union { > char cv_char; > char *cv_char_p; > char cv_char_a[4]; > short cv_short; > long cv_long; > float cv_float; > double cv_double; > short cv_short_a[4] > } cv; > } cell[10] = { > {CHAR, '?'}, > {CHAR_P, (char *)"abc"}, > {CHAR_A, (char [])"abc"}, > {CHAR_A, (char []){'a', 'b', 'c'}}, /* doesn't need the cast */ > {DOUBLE, (double)2}, > {SHORT_A, (short[]){0, 1, 2}} /* last element is 0? */ > /* If the rest of the storage is initialized to 0, > ** note that a check would show a type of UNKNOWN. > */ > }; Here is the initialization of the same struct, using the method I am proposing: struct { /* I know it doesn't have a name */ int CellType; /* holds one of the above defines */ union { char cv_char; char *cv_char_p; char cv_char_a[4]; short cv_short; long cv_long; float cv_float; double cv_double; short cv_short_a[4] } cv; } cell[10] = { {CHAR, cv_char = '?'}, {CHAR_P, cv_char_p = "abc"}, {CHAR_A, cv_char_a = "abc"}, {CHAR_A, cv_char_a = {'a', 'b', 'c'}}, {DOUBLE, cv_double = 2}, {SHORT_A, cv_short_a = {0, 1, 2}} /* last element is 0? */ /* If the rest of the storage is initialized to 0, ** note that a check would show a type of UNKNOWN. */ }; Clearer, n'est-ce pas? Both ideas are sufficient. However, I think the latter is clearer and less error-prone. Kevin Martin, UofW Software Development Group ------------------------------------------------------ End of Vol. 2, No. 8. Std-C (Jan. 10, 1985 07:15:00) -- Orlando Sotomayor-Diaz /AT&T Bell Laboratories, Red Hill Road /Middletown, New Jersey, 07748 (HR 1B 316) Tel: 201-949-9230 /UUCP: {ihnp4, houxm}!homxa!osd7