Topic: Array Elements / Struct Members


Author: skaller@users.sourceforge.net (skaller)
Date: Sun, 30 Jul 2006 05:01:20 GMT
Raw View
On Wed, 26 Jul 2006 10:04:27 -0600, wade wrote:

>
> skaller wrote:
>> apart
>> from the first element, there is no assurance that
>> the [data] members of the struct are in order!
>
> Be assured, as long as you follow the corresponding requirements.
>
> 9.2/12 "... later members have higher addresses ..."

I stand corrected! Thanks for the reference.

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Mon, 31 Jul 2006 05:07:54 GMT
Raw View
On Wed, 26 Jul 2006 14:33:14 +0000, Frederick Gotham wrote:

>
> ===================================== MODERATOR'S COMMENT:
>
> Please review the FAQ list for comp.std.c++. The moderators check only that
> postings are on-topic, cogent, and free from personal attacks. Within those
> limits, we don't evaluate the posting on technical grounds. For one thing,
> moderators are also sometimes mistaken about C++ language rules. In any case,
> the community is quick to submit corrections. :-)
>
>
> ===================================== END OF MODERATOR'S COMMENT
> skaller posted:
>
>> True, in the struct, the compiler may add padding,
>> which is not allowed in the array.
>>
>> But that's missing something equally important: apart
>> from the first element, there is no assurance that
>> the members of the struct are in order!
>
>
> Note to moderator: Where possible, may I suggest that you prohibit the
> posting of misinformation? This is the second time today that misinformation
> has been posted to this newsgroup.

I was indeed wrong. I apologise for making a false claim.
I wouldn't suggest banning misinformation in a newsgroup tho :)

> Where you have a POD, you're guaranteed that the members are laid out
> sequentially in memory, in the same order as they are defined in the struct
> definition.

I am surprised. Is that true in C as well? It is
grossly inefficient.

BTW: I wasn't referring to POD in particular.

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jdennett@acm.org (James Dennett)
Date: Mon, 31 Jul 2006 06:07:56 GMT
Raw View
skaller wrote:
> On Wed, 26 Jul 2006 14:33:14 +0000, Frederick Gotham wrote:

[snip]

>> Where you have a POD, you're guaranteed that the members are laid out
>> sequentially in memory, in the same order as they are defined in the struct
>> definition.
>
> I am surprised. Is that true in C as well?

I believe it is, though I've not checked.

> It is grossly inefficient.

It is sometimes inefficient if programmers don't know
it and code for it, but many do, for example arranging
struct members in order of size.

It's common for

struct s1
{
   char a;
   int b;
   char c;
};

to have a larger sizeof than

struct s2
{
   char a;
   char c;
   int b;
}

because of padding.

-- James

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Tue, 1 Aug 2006 03:50:03 GMT
Raw View
On Mon, 31 Jul 2006 06:07:56 +0000, James Dennett wrote:

> skaller wrote:
>> On Wed, 26 Jul 2006 14:33:14 +0000, Frederick Gotham wrote:

> It's common for
>
> struct s1
> {
>    char a;
>    int b;
>    char c;
> };
>
> to have a larger sizeof than
>
> struct s2
> {
>    char a;
>    char c;
>    int b;
> }
>
> because of padding.

. and how precisely would a code generator dealing entirely
with types T1, T2, T3, etc in the abstract arrange to do this?

For that matter a programmer not knowing the types, perhaps
using aliases like wchar_t, ptrdiff_t, size_t, etc, or some
other typedef or macro such as GLFloat (from OpenGL) .. a
practice which is common in C.

This is basically absurd. The compiler should organise the
optimisation. Actually in C++ I suppose it can be done like:

 struct s2 {
 public: char a;
 public: char c;
 public: int b;
 };

and now the C++ compiler can do a good layout (in theory).

It seems to me these language constructions are utterly
broken: the programmer does not have precise layout
control, but then the compiler doesn't have much freedom
either. One OR the other would allow for optimal layouts:
either calculated by the programmer or computed by the
compiler, respectively .. but the current rules make
both impossible (without hackery).

I guess you could achieve these things with annotations
such as:

 struct packed ..  // no padding, no matter what
 struct bitpacked .. // extreme form!
 struct ordered .. // keep elements in order

etc .. which would give C++ an edge over C :)

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Fri, 28 Jul 2006 08:38:26 CST
Raw View
Frederick Gotham wrote:
..
> I don't get this one:
>
> 6.7 p4: a local static POD object declared with initializers is
> initialized before its block is first entered.
>
> How could that be possible if you had the following?
>
> struct MyPOD { int i, j; };
>
> int GetValue() { return 3; }
>
> int main()
> {
>     int i = GetValue();
>     int j = GetValue();
>
>     MyPOD static obj = { i, j };
> }

Sorry, when I wrote that many years ago, I was just trying to summarize
the meaning of each item, not to provide a complete statement of it. If
you follow up the citation I gave, you'll see that this guarantee only
applies when the initializers are constant expressions. Specitying that
in my summary could have been achieved by adding four more words, but I
was trying to keep the summaries as brief as possible.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Fri, 28 Jul 2006 10:05:29 CST
Raw View
Frederick Gotham wrote:
> Jack Klein posted:
>
> > There are several ways to deal with providing "prettier" or
> > "more meaningful" names in the source code.
>
>
> Yes, but the canonical way is inefficient on many implementations, plus the
> struct is no longer a POD:
>
> struct Arb {
>
>     unsigned char colours[4];
>
>     unsigned char &r;
>     unsigned char &g;
>     unsigned char &b;
>     unsigned char &x;
>
>     Arb() : r(*colours), g(colours[1]...
>
> };
>
That's not because there are bad solutions to this problem that there
is no good solution!
Jack Klein exposed a macro solution, and an enum solution.
There are other correct solutions:

Accessors : Hey we're on comp.std.c++, accessors are a mean to abstract
layout.

struct Arb {
  enum {red_,green_,blue_, alpha_};
  unsigned char colors[4];
  unsigned char& red() {return colors[red_];}
  const unsigned char& red() const {return colors[red_];}
  unsigned char& green() {return colors[green_];}
  const unsigned char& green() const {return colors[green_];}
  unsigned char& blue() {return colors[blue_];}
  const unsigned char& blue() const {return colors[blue_];}
  unsigned char& alpha() {return colors[alpha_];}
  const unsigned char& alpha() const {return colors[alpha_];}
};
Note:
Other styles of accessors such as:

unsigned char red() const {return colors[red_];}
void red(unsigned char value) const {colors[red_]=value;}

Or
unsigned char GetRed() const {return colors[red_];}
void SetRed(unsigned char value) {colors[red_]=value;}

Are not a correct solution, since we may want to be able to get the
address of these fields:

unsigned char* pred=&str.red();


It is verbose, due to the const correctness.
But
1) This problem is seldom; So verbosity is not that much a problem.
2) Again, macros can help... And they work wonderfully here.
/* avoids problem when the type is something like int[42] */
template <class T>
struct TypeFromMacro {
  typedef T value_type;
};

/* all caps macro; Name clash risk is small */
#define DEFINE_ARRAY_ACCESSOR(type, field_name, array_name,
array_index) \
const TypeFromMacro<type>::value_type& field_name() const {\
  return array_name[array_index];\
}\
TypeFromMacro<type>::value_type& field_name() {\
  return array_name[array_index];\
}

#define ARRAY_ACCESSOR(type, array_name, field_name)\
DEFINE_ARRAY_ACCESSOR(type, field_name, array_name, field_name##_)

struct Arb {
  enum {red_,green_,blue_, alpha_};
  unsigned char colors[4];
  ARRAY_ACCESSOR(unsigned char, colors, red)
  ARRAY_ACCESSOR(unsigned char, colors, green)
  ARRAY_ACCESSOR(unsigned char, colors, blue)
  ARRAY_ACCESSOR(unsigned char, colors, alpha)
};

And you can define macros for defining several fields at a time:
#define ARRAY_ACCESSOR2(type, array, field_name1, field_name2)\
ARRAY_ACCESSOR(type, array, field_name1)\
ARRAY_ACCESSOR(type, array, field_name2)

#define ARRAY_ACCESSOR3(type, array, field_name1, field_name2,
field_name3)\
ARRAY_ACCESSOR(type, array, field_name1)\
ARRAY_ACCESSOR(type, array, field_name2)\
ARRAY_ACCESSOR(type, array, field_name3)

#define ARRAY_ACCESSOR4(type, array, f1, f2, f3, f4)\
ARRAY_ACCESSOR2(type, array, f1, f2)\
ARRAY_ACCESSOR2(type, array, f3, f4)

struct Arb {
  enum {red_,green_,blue_, alpha_};
  unsigned char colors[4];
  ARRAY_ACCESSOR4(unsigned char, colors, red, green, blue, alpha)
};

Now, I think it is no more verbose.
Even if you have 8 fields, in three lines, you'll get it.

Reordering fields is as easy as with your proposal : Simply reorder
them in the enum declaration.

I think we don't need a language feature for that!

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: skaller@users.sourceforge.net (skaller)
Date: Wed, 26 Jul 2006 06:05:48 GMT
Raw View
On Tue, 25 Jul 2006 14:34:47 +0000, Jack Klein wrote:

> On Mon, 24 Jul 2006 15:56:37 GMT, fgothamNO@SPAM.com (Frederick
> Gotham) wrote in comp.std.c++:
>
>>
>> Firstly I'll give a brief intro. Many people have expressed an interest in
>> being able to give meaningful names to array elements, such that they have
>> the choice of referring to the object either by its name, or by its index.

> Yes, people have expressed an interest in this, but it is for
> esthetics or a genuine improvement to the language?

I have a need for this too, and indeed rely on it.
The requirement is not 'prettiness' but layout compatibility.

Thus in the discussion the original poster missed out
on a key part of the problem, when referring to padding!

True, in the struct, the compiler may add padding,
which is not allowed in the array.

But that's missing something equally important: apart
from the first element, there is no assurance that
the members of the struct are in order!

I would therefore propose that a struct all of whose members
are the same type shall be required to be layed out
with the members in sequence and without any gratuitous
padding, so that these elements are at the same addresses
as the corresponding array elements.

In the Felix compiler, an array is just a tuple.
Tuple is modelled by a struct like:

 struct tname {
  T1 mem_1;
  T2 mem_2;
  ...
 };

and array is modelled by

 struct aname {
  T1 data[n];
 };

and the compiler uses a 'reference cast' to overlay
one on the other, on the assumption they're layout compatible.

There is no requirement in the ISO C or C++ Standards that
this be the case.

The sequencing can be ensured by nesting:

 struct tname {
  T1 mem_1;
  struct tname2 {
   T2 mem_2;
   struct tname3 { ... } s3;
  } s2;
 };

since the 'first member of a struct has the same address
as the struct' rule now guarantees that mem1, mem2, mem3
are allocated in monotonically increasing storage locations,
as with the array elements.. but there is still no assurance
gratuitous padding isn't introduced (as you point out).

This is NOT just a matter of aesthetics .. unless you consider
it is realistic to just use placement new and offset calculations
with casts to completely eliminate the need for structs..
this can be done (modulo alignment issues) but doesn't look pretty:
you might as well write code in assembly .. :)

Unless you allow that then NO, it is NOT a matter of aesthetics
at all, but a reasonable requirement which allows aliasing two
distinct types by virtue of a guarantee the types are layout
compatible. As mentioned .. this is actually used in a production
compiler that claims to generate strictly ISO C/C++ conformant
code 'bar some caveats' and this is one of the caveats.

I note in passing the 'array' representation has a serious
defect -- there is no way to initialise an array except with
default constructors. Again, since the Felix code generator
uses constructors to initialise tuple objects, but tuples
of the same type are modelled with the above array representation,
the cast is essential -- otherwise the array would have to
be initialised by assignments AND there would need to be
a constructor accepting n arguments. The latter requirement
doesn't generalise to 1 million element arrays .. but of course
a code generator has to work according to strict algorithms.

The actual solution .. is to use a tuple form for the special
case the client use a tuple constructor like '(1,2)' and
cast it to the array form .. thus providing the array form
with a real constructor for all those cases where the
constructor is required .. but not otherwise.

--
John Skaller <skaller at users dot sf dot net>
Try Felix, the successor to C++ http://felix.sf.net


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: fgothamNO@SPAM.com (Frederick Gotham)
Date: Wed, 26 Jul 2006 14:33:14 GMT
Raw View
===================================== MODERATOR'S COMMENT:

Please review the FAQ list for comp.std.c++. The moderators check only that
postings are on-topic, cogent, and free from personal attacks. Within those
limits, we don't evaluate the posting on technical grounds. For one thing,
moderators are also sometimes mistaken about C++ language rules. In any case,
the community is quick to submit corrections. :-)


===================================== END OF MODERATOR'S COMMENT
skaller posted:

> True, in the struct, the compiler may add padding,
> which is not allowed in the array.
>
> But that's missing something equally important: apart
> from the first element, there is no assurance that
> the members of the struct are in order!


Note to moderator: Where possible, may I suggest that you prohibit the
posting of misinformation? This is the second time today that misinformation
has been posted to this newsgroup.

Where you have a POD, you're guaranteed that the members are laid out
sequentially in memory, in the same order as they are defined in the struct
definition.

struct Arb {
    int a;
    char b;
    double c;
    float d;
};

int main()
{
    Arb obj;

    assert(&obj.d > &obj.c > &obj.b > &obj.a);
}

Could someone please point me to the post which lists the twenty-something
guarantees we have for POD types... I couldn't find it using Google Groups
search.

--

Frederick Gotham

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: wade@stoner.com
Date: Wed, 26 Jul 2006 10:04:27 CST
Raw View
skaller wrote:
> apart
> from the first element, there is no assurance that
> the [data] members of the struct are in order!

Be assured, as long as you follow the corresponding requirements.

9.2/12 "... later members have higher addresses ..."

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: wade@stoner.com
Date: Wed, 26 Jul 2006 10:04:43 CST
Raw View
skaller wrote:

> I would therefore propose that a struct all of whose members
> are the same type shall be required to be layed out
> with the members in sequence and without any gratuitous
> padding, so that these elements are at the same addresses
> as the corresponding array elements.
>
>  struct tname {
>   T1 mem_1;
>   T1 mem_2;
>   ...
>                              T1 mem_99;
>  };

I think the proposal is reasonable, since it is what all compilers that
I am aware of do.

Of course if you are using C++ as an intermediate language (perhaps
generated by some IDL), the proposal buys you very little.  The
standard already guarantees the elements are in declaration order,
existing compilers don't perform gratuitous padding, and you can use
compile time asserts to catch any hypothetical compiler that does do
interior padding.  If T1 is a struct (or union or array of struct),
assert that sizeof(tname) == 99*sizeof(T1).  If T1 is a scalar,
pointer, or array of scalar/pointer, then tname is POD, and you can
assert that offset of mem_99 is 98 * sizeof(T1).

However, for hand-generated code, counting to 99 is a pain, so having
the guarantee in the standard would be a benefit.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: fgothamNO@SPAM.com (Frederick Gotham)
Date: Wed, 26 Jul 2006 15:50:42 GMT
Raw View
skaller posted:

> I would therefore propose that a struct all of whose members
> are the same type shall be required to be layed out
> with the members in sequence and without any gratuitous
> padding, so that these elements are at the same addresses
> as the corresponding array elements.


That would be inefficient on architectures where the smallest addressable
unit in memory is greater than a byte:

    unsigned i = Access2Bytes();

    unsigned char byte1 = i & UCHAR_MAX;

    unsigned char byte2 = i & UCHAR_MAX << CHAR_BIT;


On such a system, it would be efficient to represent:

struct Arb {
    char a;
    char b;
    char c;
    char d;
};

as:

struct Arb {
    char a;
    char padding1;
    char b;
    char padding2;
    char c;
    char padding3;
    chad d;
    char padding4;
};

--

Frederick Gotham

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Wed, 26 Jul 2006 22:56:08 CST
Raw View
Frederick Gotham wrote:
.
> Could someone please point me to the post which lists the twenty-something
> guarantees we have for POD types... I couldn't find it using Google Groups
> search.

That's mine. I've posted it three times now, the first time was in
September 1999:
<http://groups.google.com/group/comp.std.c++/msg/663f0eb1635ed9c2?hl=en&>

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: fgothamNO@SPAM.com (Frederick Gotham)
Date: Thu, 27 Jul 2006 14:57:28 GMT
Raw View
 posted:

> Frederick Gotham wrote:
> .
>> Could someone please point me to the post which lists the twenty-
something
>> guarantees we have for POD types... I couldn't find it using Google
Groups
>> search.
>
> That's mine. I've posted it three times now, the first time was in
> September 1999:
><http://groups.google.com/group/comp.std.c++/msg/663f0eb1635ed9c2?hl=en&>


Much obliged :).

I don't get this one:

6.7 p4: a local static POD object declared with initializers is
initialized before its block is first entered.

How could that be possible if you had the following?

struct MyPOD { int i, j; };

int GetValue() { return 3; }

int main()
{
    int i = GetValue();
    int j = GetValue();

    MyPOD static obj = { i, j };
}

--

Frederick Gotham

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: fgothamNO@SPAM.com (Frederick Gotham)
Date: Mon, 24 Jul 2006 15:56:37 GMT
Raw View
Firstly I'll give a brief intro. Many people have expressed an interest in
being able to give meaningful names to array elements, such that they have
the choice of referring to the object either by its name, or by its index.
As follows:

struct MyPOD {
    char a;
    char b;
    char c;
    char d;
};

int main()
{
    MyPOD obj;

    char *p = reinterpret_cast<char*>(&obj);

    *p++ = 1;  /* Changes a */
    *p++ = 2;  /* Changes b */
    *p++ = 3;  /* Changes c */
    *p++ = 4;  /* Changes d */


    /* Or perhaps the following */

    char *const p = reinterpret_cast<char*>(&obj);

    p[0] = 1;  /* Changes a */
    p[1] = 2;  /* Changes b */
    p[2] = 3;  /* Changes c */
    p[3] = 4;  /* Changes d */
}


The idea is that we can give meaningful names to array elements.

Alas, the code is non-portable as the implementation may place padding
between the struct members (perhaps for optimisation on systems where a
byte can't be accessed individually).

What I would propose is that we have some way of indicating that there
shall be no inter-member padding. Firstly, commas would be used to indicate
which members participate as elements in the array:

struct MyPOD {
    char a,b,c,d;
};

And then perhaps a keyword to indicate the absence of inter-member padding:

struct MyPOD {
    char a,b,c,d : explicit;
};

This could be combined with a union to yield code such as the following:

union MyPOD {

    char array[4];

    struct {
        char a,b,c,d : explicit;
    };

    /* Allow anonymous struct */
};


int main()
{
    MyPOD obj;

    obj.array[0] = 1;
    obj.array[1] = 2;
    obj.array[2] = 3;
    obj.array[3] = 4;

    obj.a = 1;
    obj.b = 2;
    obj.c = 3;
    obj.d = 4;
}

--

Frederick Gotham

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: jackklein@spamcop.net (Jack Klein)
Date: Tue, 25 Jul 2006 14:34:47 GMT
Raw View
On Mon, 24 Jul 2006 15:56:37 GMT, fgothamNO@SPAM.com (Frederick
Gotham) wrote in comp.std.c++:

>
> Firstly I'll give a brief intro. Many people have expressed an interest in
> being able to give meaningful names to array elements, such that they have
> the choice of referring to the object either by its name, or by its index.
> As follows:
>
> struct MyPOD {
>     char a;
>     char b;
>     char c;
>     char d;
> };
>
> int main()
> {
>     MyPOD obj;
>
>     char *p = reinterpret_cast<char*>(&obj);
>
>     *p++ = 1;  /* Changes a */
>     *p++ = 2;  /* Changes b */
>     *p++ = 3;  /* Changes c */
>     *p++ = 4;  /* Changes d */
>
>
>     /* Or perhaps the following */
>
>     char *const p = reinterpret_cast<char*>(&obj);
>
>     p[0] = 1;  /* Changes a */
>     p[1] = 2;  /* Changes b */
>     p[2] = 3;  /* Changes c */
>     p[3] = 4;  /* Changes d */
> }

I have snipped a good part of your post because I quoted your entire
post about POD structs.

Once again I need to raise the issues of C and possible OS/third party
library compatibility issues, and whether this is worth it.

Yes, people have expressed an interest in this, but it is for
esthetics or a genuine improvement to the language?  If an array of n
elements happens to have a smaller size than an equivalent POD struct
with n individually named members of the same type, and the size
matters that much because you have so many of them, merely use the
array.  There are several ways to deal with providing "prettier" or
"more meaningful" names in the source code.

Years ago, in embedded systems, I had to deal with packing multiple
objects of different types into very small spaces, especially in
embedded systems.  By small spaces, I mean for example an EEPROM with
128 bytes of 8 bits each.  And allow a communication interface to get
and set individual values on an 8-bit microcontroller that did not
have the code space for parsing anything other than array subscripts.

Yet I wanted to have meaningful names in the source code where these
values were used.

Consider a made up struct for this example:

struct pixel_32
{
   unsigned char colors [4];
};

.where a "more meaningful" definition might be:

struct pixel_32
{
   unsigned char red_val;
   unsigned char green_val;
   unsigned char blue_val;
   unsigned char unused;
};

Here's the type of solution that worked long ago in C, even before
"enum" was added to the language:

In a header...

#define red_val colors[0]
#define green_val colors[1]
#define blue_val colors[2]
#define unused colors[3]

.name these ALL CAPS if you prefer, but for this type of macro I
specifically decided to break the ALL CAP macro rule.

And then:

struct pixel_32 pixel;

pixel.red_val = 255;
pixel.green_val = 255;
pixel.blue_val = 0;

.sets the pixel to the value for bright yellow quite nicely.

Macros are icky, always to be avoided, right?  Perhaps not always,
occasionally they can actually make code more clearly match the
intent.

Nowadays, with enumerations in both C and C++, this could be:

enum (red_val, green_val, blue_val, unused );

.in C++ this can be scoped to the POD struct by defining it within
the struct definition.

Then you can write:

pixel.colors[red_val] = 255; /* etc. */

In C++, you can even replace the enum with "const int".

To my way of thinking, the macro implementation actually results in
the cleanest, most elegant source code.  It looks just like having the
readability of a descriptive member name, and the guaranteed adjacency
of an array.

Given that there are "tricks" that give all the source readability of
your proposal, though you may dislike them, the same question arises
as for your other proposal.  Can you make a compelling case for a
significant gain for a significant percentage of programs to justify a
major change in the language definition, and potentially some
significant work on the part of vendors of at least some
implementations?

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Frederick Gotham <fgothamNO@SPAM.com>
Date: Tue, 25 Jul 2006 10:56:45 CST
Raw View
Jack Klein posted:

> There are several ways to deal with providing "prettier" or
> "more meaningful" names in the source code.


Yes, but the canonical way is inefficient on many implementations, plus the
struct is no longer a POD:

struct Arb {

    unsigned char colours[4];

    unsigned char &r;
    unsigned char &g;
    unsigned char &b;
    unsigned char &x;

    Arb() : r(*colours), g(colours[1]...

};

--

Frederick Gotham

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]