Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > compound literals

Reply
Thread Tools

compound literals

 
 
Mantorok Redgormor
Guest
Posts: n/a
 
      09-14-2003
What is the point of them?

When should I use them?

They seem to be rather useless but hopefully someone can prove me
wrong. I think they are just additions to c99 but didn't exist in
c89/90.


Also, when is it appropriate to cast? Casting seems to be frowned up
on so it makes me wonder when it is appropriate to ever cast.
 
Reply With Quote
 
 
 
 
Nick Austin
Guest
Posts: n/a
 
      09-14-2003
On 13 Sep 2003 22:35:51 -0700, http://www.velocityreviews.com/forums/(E-Mail Removed) (Mantorok Redgormor)
wrote:

>What is the point of them?
>
>When should I use them?


Passing an argument to a function without using a temporary:

foo( (struct bar){ 1, 2 } );

Adding storage qualifiers:

(const char[]){ "foo" }

Nick.

 
Reply With Quote
 
 
 
 
Kevin Bracey
Guest
Posts: n/a
 
      09-15-2003
In message <(E-Mail Removed) >
(E-Mail Removed) (Mantorok Redgormor) wrote:

> What is the point of them?
>
> When should I use them?
>
> They seem to be rather useless but hopefully someone can prove me
> wrong. I think they are just additions to c99 but didn't exist in
> c89/90.


They are new in C99 (and hence don't exist in C++ either).

They're not a massively useful construct, but when you do find an application
for them, they can help tidy up code quite well. Here are two real-life
examples, from some SCSI software:

/* Array literal constants defining well-known SCSI commands */
#define CDB_TEST_READY ((const uint8_t[6]) { 0x00 })
#define CDB_INQUIRY_L ((const uint8_t[6]) { 0x12, 0, 0, 0, 36, 0 })
#define CDB_CAPACITY ((const uint8_t[10]) { 0x25 })

With these defines, a whole SCSI command can be simply defined and passed
to an API by giving the macro name, without having to manually declare and
initialise a variable.

Now a more complex example, which will lead in nicely to your cast question.
The software internally uses error codes (from 0-255), but has to supply the
outside world with a pointer to an error structure (consisting of a code,
followed by a variable length string). A simple (!) form of knocking up a
mapping table, ignoring internationalisation issues, can work as follows:

--- errors.h ---

// typedef struct { int errnum; char errmess[252]; } oserror;

#define SCSI_ErrorBase 0x20100

enum
{
SCSI_NoRoom = 0x00,
SCSI_SWIunkn,
SCSI_RCunkn,
...
};

oserror *scsi_error(unsigned err);

--- errors.c ---

#define ErrType(str) const struct { int errnum; char errmess[sizeof str]; }
#define ErrBlock(num, str) (ErrType(str)) { num, str }
#define ErrEntry(num, str) [num] = (oserror *) &ErrBlock(SCSI_ErrorBase+num,str)

static oserror * const errtable[256] =
{
ErrEntry(SCSI_NoRoom, "No room for SCSI driver workspace"),
ErrEntry(SCSI_SWIunkn, "Unknown SCSI SWI number"),
ErrEntry(SCSI_RCunkn, "Unknown reason code for SCSI SWI"),
...
};

oserror *scsi_error(unsigned err)
{
if (err >= 256) return (oserror *) err;

if (errtable[err]) return errtable[err];

return scsi_error(SCSI_InvalidParms);
}

If you pick through the macro definitions, you'll note that this also uses
designated initialisers, another C99 feature, to match the errtable array
entries to the enum. Also be aware that the code is not portable for other
reasons (mentioned below).

> Also, when is it appropriate to cast? Casting seems to be frowned up
> on so it makes me wonder when it is appropriate to ever cast.


Casting is generally frowned upon, yes, as it is usually unnecessary - if you
find yourself needing to cast you're probably doing something non-portable or
you're patching over an error. Here are some examples, in ascending order of
frown-factor.

It can be used straightforwardly to perform a conversion (eg manually
converting a float to an int), but this is usually not required, as implicit
conversions happen on assignment and when passing values to prototyped
functions. You might need casts in expressions; one valid example might be:

int m = <whatever>, n = <whatever>;
float ratio = (float) m / (float) n;

Without the casts, the division would be performed as an integer division.

It can be used to fudge qualifiers like "const" - for example a definition of
strchr (from <string.h>) would have to have a cast to coerce the "const char
*" passed in into a returned "char *".

It can be used to change the interpretation of a pointer (eg the cast of the
arbitrary sized compound literal to oserror * in the ErrEntry macro above) -
this sort of casting is only valid if you know that the thing being pointed
to can be accessed through the new type of pointer; C gives some assurances
about when this works, eg when structures have common initial members, but
otherwise you have to be careful when writing portable code.

Most dubiously, you can convert between fundamentally different types - eg
the cast of an unsigned to an oserror * in the scsi_error function. That is
definitely non-portable. Don't do it.

--
Kevin Bracey, Principal Software Engineer
Tematic Ltd Tel: +44 (0) 1223 503464
182-190 Newmarket Road Fax: +44 (0) 1223 503458
Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/
 
Reply With Quote
 
Mantorok Redgormor
Guest
Posts: n/a
 
      09-16-2003
Kevin Bracey <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> In message <(E-Mail Removed) >
> (E-Mail Removed) (Mantorok Redgormor) wrote:
>
> > What is the point of them?
> >
> > When should I use them?
> >
> > They seem to be rather useless but hopefully someone can prove me
> > wrong. I think they are just additions to c99 but didn't exist in
> > c89/90.

>
> They are new in C99 (and hence don't exist in C++ either).
>
> They're not a massively useful construct, but when you do find an application
> for them, they can help tidy up code quite well. Here are two real-life
> examples, from some SCSI software:
>
> /* Array literal constants defining well-known SCSI commands */
> #define CDB_TEST_READY ((const uint8_t[6]) { 0x00 })
> #define CDB_INQUIRY_L ((const uint8_t[6]) { 0x12, 0, 0, 0, 36, 0 })
> #define CDB_CAPACITY ((const uint8_t[10]) { 0x25 })
>
> With these defines, a whole SCSI command can be simply defined and passed
> to an API by giving the macro name, without having to manually declare and
> initialise a variable.
>
> Now a more complex example, which will lead in nicely to your cast question.
> The software internally uses error codes (from 0-255), but has to supply the
> outside world with a pointer to an error structure (consisting of a code,
> followed by a variable length string). A simple (!) form of knocking up a
> mapping table, ignoring internationalisation issues, can work as follows:
>
> --- errors.h ---
>
> // typedef struct { int errnum; char errmess[252]; } oserror;
>
> #define SCSI_ErrorBase 0x20100
>
> enum
> {
> SCSI_NoRoom = 0x00,
> SCSI_SWIunkn,
> SCSI_RCunkn,
> ...
> };
>
> oserror *scsi_error(unsigned err);
>
> --- errors.c ---
>
> #define ErrType(str) const struct { int errnum; char errmess[sizeof str]; }
> #define ErrBlock(num, str) (ErrType(str)) { num, str }
> #define ErrEntry(num, str) [num] = (oserror *) &ErrBlock(SCSI_ErrorBase+num,str)
>
> static oserror * const errtable[256] =
> {
> ErrEntry(SCSI_NoRoom, "No room for SCSI driver workspace"),
> ErrEntry(SCSI_SWIunkn, "Unknown SCSI SWI number"),
> ErrEntry(SCSI_RCunkn, "Unknown reason code for SCSI SWI"),
> ...
> };
>
> oserror *scsi_error(unsigned err)
> {
> if (err >= 256) return (oserror *) err;
>
> if (errtable[err]) return errtable[err];
>
> return scsi_error(SCSI_InvalidParms);
> }
>
> If you pick through the macro definitions, you'll note that this also uses
> designated initialisers, another C99 feature, to match the errtable array
> entries to the enum. Also be aware that the code is not portable for other
> reasons (mentioned below).
>
> > Also, when is it appropriate to cast? Casting seems to be frowned up
> > on so it makes me wonder when it is appropriate to ever cast.

>
> Casting is generally frowned upon, yes, as it is usually unnecessary - if you
> find yourself needing to cast you're probably doing something non-portable or
> you're patching over an error. Here are some examples, in ascending order of
> frown-factor.
>
> It can be used straightforwardly to perform a conversion (eg manually
> converting a float to an int), but this is usually not required, as implicit
> conversions happen on assignment and when passing values to prototyped
> functions. You might need casts in expressions; one valid example might be:
>
> int m = <whatever>, n = <whatever>;
> float ratio = (float) m / (float) n;
>
> Without the casts, the division would be performed as an integer division.
>
> It can be used to fudge qualifiers like "const" - for example a definition of
> strchr (from <string.h>) would have to have a cast to coerce the "const char
> *" passed in into a returned "char *".
>
> It can be used to change the interpretation of a pointer (eg the cast of the
> arbitrary sized compound literal to oserror * in the ErrEntry macro above) -
> this sort of casting is only valid if you know that the thing being pointed
> to can be accessed through the new type of pointer; C gives some assurances
> about when this works, eg when structures have common initial members, but
> otherwise you have to be careful when writing portable code.
>
> Most dubiously, you can convert between fundamentally different types - eg
> the cast of an unsigned to an oserror * in the scsi_error function. That is
> definitely non-portable. Don't do it.


Thanks for the great post! Very informative.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Compound literals (anonymous aggregates) kid joe C Programming 21 04-25-2009 07:01 PM
Compound literals efficiency Marcus Harnisch C Programming 10 01-12-2009 01:56 PM
Java: byte literals and short literals John Goche Java 8 01-17-2006 11:12 PM
Compound literals and VLA's William Ahern C Programming 6 08-24-2005 05:40 AM
RE: Compound Control event not firing, but only when it's in a library =?Utf-8?B?TWlrZUw=?= ASP .Net 0 11-19-2004 04:45 AM



Advertisments