Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #59410 > unrolled thread

struct tag (*[5])(float)

Started by"James Harris" <james.harris.1@gmail.com>
First post2015-04-01 21:17 +0100
Last post2015-04-02 15:22 -0700
Articles 11 — 7 participants

Back to article view | Back to comp.lang.c


Contents

  struct tag (*[5])(float) "James Harris" <james.harris.1@gmail.com> - 2015-04-01 21:17 +0100
    Re: struct tag (*[5])(float) James Kuyper <jameskuyper@verizon.net> - 2015-04-01 17:40 -0400
      Re: struct tag (*[5])(float) Bartc <bc@freeuk.com> - 2015-04-01 22:55 +0100
        Re: struct tag (*[5])(float) Barry Schwarz <schwarzb@dqel.com> - 2015-04-01 16:01 -0700
          Re: struct tag (*[5])(float) James Kuyper <jameskuyper@verizon.net> - 2015-04-01 19:29 -0400
            Re: struct tag (*[5])(float) Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-04-02 05:28 -0700
          Re: struct tag (*[5])(float) Bartc <bc@freeuk.com> - 2015-04-02 00:37 +0100
        Re: struct tag (*[5])(float) Keith Thompson <kst-u@mib.org> - 2015-04-01 20:13 -0700
          Re: struct tag (*[5])(float) Bartc <bc@freeuk.com> - 2015-04-02 10:30 +0100
            Re: struct tag (*[5])(float) Keith Thompson <kst-u@mib.org> - 2015-04-02 15:18 -0700
    Re: struct tag (*[5])(float) John Bode <jfbode1029@gmail.com> - 2015-04-02 15:22 -0700

#59410 — struct tag (*[5])(float)

From"James Harris" <james.harris.1@gmail.com>
Date2015-04-01 21:17 +0100
Subjectstruct tag (*[5])(float)
Message-ID<mfhjtf$plc$1@dont-email.me>
The type

  struct tag (*[5])(float)

appears in at least two draft C standards: for C89 and the n869 pdf. I 
find it hard to read because it has no identifier. I can see where an 
identifier can be placed but how is a programmer *supposed* to parse 
such a "type" when reading a standard? Is it as simple as knowing which 
symbols are prefixes and which would be suffixes?

James

[toc] | [next] | [standalone]


#59412

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-04-01 17:40 -0400
Message-ID<551C65E3.8010903@verizon.net>
In reply to#59410
On 04/01/2015 04:17 PM, James Harris wrote:
> The type
> 
>   struct tag (*[5])(float)
> 
> appears in at least two draft C standards: for C89 and the n869 pdf. I 
> find it hard to read because it has no identifier. I can see where an 
> identifier can be placed but how is a programmer *supposed* to parse 
> such a "type" when reading a standard? Is it as simple as knowing which 
> symbols are prefixes and which would be suffixes?
> 
> James

What you are talking about is described in 6.7.7p2:
"In several contexts, it is necessary to specify a type. This is
accomplished using a _type name_, which is syntactically a declaration
for a function or an object of that type that omits the identifier.".
I'm using underscores to mark the fact that "type name" is in italics, a
convention used in ISO standards to indicate that the clause it appears
in is, officially, the definition for the italicized term.

Whenever a type name is allowed, if the code that you're parsing matches
one of the grammar productions in 6.7.7p1, then it is a type name. Since
and identifier qualifies as a direct-declarator (6.7.6p1), but does NOT
qualify as a direct-abstract-declarator (6.7.7p1), in order to match
those grammar rules, you must sooner or later parse it down to the point
where an optional abstract-declarator or direct-abstract-declarator is
missing - and that's precisely where the missing identifier would go.
Insert an arbitrary dummy identifier in that location, and the type name
should make sense as a declaration.

The examples given in 6.7p3 might help clarify this issue.

[toc] | [prev] | [next] | [standalone]


#59413

FromBartc <bc@freeuk.com>
Date2015-04-01 22:55 +0100
Message-ID<mfhpfk$g36$1@dont-email.me>
In reply to#59412
On 01/04/2015 22:40, James Kuyper wrote:
> On 04/01/2015 04:17 PM, James Harris wrote:
>> The type
>>
>>    struct tag (*[5])(float)
>>
>> appears in at least two draft C standards: for C89 and the n869 pdf. I
>> find it hard to read because it has no identifier. I can see where an
>> identifier can be placed but how is a programmer *supposed* to parse
>> such a "type" when reading a standard? Is it as simple as knowing which
>> symbols are prefixes and which would be suffixes?
>>
>> James
>
> What you are talking about is described in 6.7.7p2:
> "In several contexts, it is necessary to specify a type. This is
> accomplished using a _type name_, which is syntactically a declaration
> for a function or an object of that type that omits the identifier.".
> I'm using underscores to mark the fact that "type name" is in italics, a
> convention used in ISO standards to indicate that the clause it appears
> in is, officially, the definition for the italicized term.
>
> Whenever a type name is allowed, if the code that you're parsing matches
> one of the grammar productions in 6.7.7p1, then it is a type name. Since
> and identifier qualifies as a direct-declarator (6.7.6p1), but does NOT
> qualify as a direct-abstract-declarator (6.7.7p1), in order to match
> those grammar rules, you must sooner or later parse it down to the point
> where an optional abstract-declarator or direct-abstract-declarator is
> missing - and that's precisely where the missing identifier would go.
> Insert an arbitrary dummy identifier in that location, and the type name
> should make sense as a declaration.
>
> The examples given in 6.7p3 might help clarify this issue.

But is a human reader supposed to do keep all this in mind? It should be 
instantly obvious!

I know there is an informal algorithm that can be used (and that people 
used to keep posting whenever I complained about complex typespecs), but 
I could never get it and just resorted to Cdecl instead. However the 
online Cdecl I used is no longer available, and I have to use trial and 
error.

I could try and tell you what the above means, but it will a guess. 
Although I know the name goes just before the "*", because I tested my 
guess with a compiler.

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#59415

FromBarry Schwarz <schwarzb@dqel.com>
Date2015-04-01 16:01 -0700
Message-ID<cotohattrq2loq8eqvj757qiuhkaorga1s@4ax.com>
In reply to#59413
On Wed, 01 Apr 2015 22:55:50 +0100, Bartc <bc@freeuk.com> wrote:

>On 01/04/2015 22:40, James Kuyper wrote:
>> On 04/01/2015 04:17 PM, James Harris wrote:
>>> The type
>>>
>>>    struct tag (*[5])(float)
>>>
>>> appears in at least two draft C standards: for C89 and the n869 pdf. I
>>> find it hard to read because it has no identifier. I can see where an
>>> identifier can be placed but how is a programmer *supposed* to parse
>>> such a "type" when reading a standard? Is it as simple as knowing which
>>> symbols are prefixes and which would be suffixes?
>>>
>>> James
>>
>> What you are talking about is described in 6.7.7p2:
>> "In several contexts, it is necessary to specify a type. This is
>> accomplished using a _type name_, which is syntactically a declaration
>> for a function or an object of that type that omits the identifier.".
>> I'm using underscores to mark the fact that "type name" is in italics, a
>> convention used in ISO standards to indicate that the clause it appears
>> in is, officially, the definition for the italicized term.
>>
>> Whenever a type name is allowed, if the code that you're parsing matches
>> one of the grammar productions in 6.7.7p1, then it is a type name. Since
>> and identifier qualifies as a direct-declarator (6.7.6p1), but does NOT
>> qualify as a direct-abstract-declarator (6.7.7p1), in order to match
>> those grammar rules, you must sooner or later parse it down to the point
>> where an optional abstract-declarator or direct-abstract-declarator is
>> missing - and that's precisely where the missing identifier would go.
>> Insert an arbitrary dummy identifier in that location, and the type name
>> should make sense as a declaration.
>>
>> The examples given in 6.7p3 might help clarify this issue.
>
>But is a human reader supposed to do keep all this in mind? It should be 
>instantly obvious!
>
>I know there is an informal algorithm that can be used (and that people 
>used to keep posting whenever I complained about complex typespecs), but 
>I could never get it and just resorted to Cdecl instead. However the 
>online Cdecl I used is no longer available, and I have to use trial and 
>error.
>
>I could try and tell you what the above means, but it will a guess. 
>Although I know the name goes just before the "*", because I tested my 
>guess with a compiler.

I think you guessed wrong.  The name goes between the * and the [.
Without the name, it specifies the type
     array of five pointer-to-function

Where each function pointed to
          takes one argument of type float
          returns a value of type struct tag

With the name and a concluding ;, it would declare (and possibly
define) an array object of that type.

-- 
Remove del for email

[toc] | [prev] | [next] | [standalone]


#59416

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-04-01 19:29 -0400
Message-ID<551C7F62.50701@verizon.net>
In reply to#59415
On 04/01/2015 07:01 PM, Barry Schwarz wrote:
> On Wed, 01 Apr 2015 22:55:50 +0100, Bartc <bc@freeuk.com> wrote:
> 
>> On 01/04/2015 22:40, James Kuyper wrote:
...
>>> What you are talking about is described in 6.7.7p2:
>>> "In several contexts, it is necessary to specify a type. This is
>>> accomplished using a _type name_, which is syntactically a declaration
>>> for a function or an object of that type that omits the identifier.".
>>> I'm using underscores to mark the fact that "type name" is in italics, a
>>> convention used in ISO standards to indicate that the clause it appears
>>> in is, officially, the definition for the italicized term.
>>>
>>> Whenever a type name is allowed, if the code that you're parsing matches
>>> one of the grammar productions in 6.7.7p1, then it is a type name. Since
>>> and identifier qualifies as a direct-declarator (6.7.6p1), but does NOT
>>> qualify as a direct-abstract-declarator (6.7.7p1), in order to match
>>> those grammar rules, you must sooner or later parse it down to the point
>>> where an optional abstract-declarator or direct-abstract-declarator is
>>> missing - and that's precisely where the missing identifier would go.
>>> Insert an arbitrary dummy identifier in that location, and the type name
>>> should make sense as a declaration.
>>>
>>> The examples given in 6.7p3 might help clarify this issue.
>>
>> But is a human reader supposed to do keep all this in mind? It should be 
>> instantly obvious!

For me, it usually is - but I've been programming in C since around 1980.

>> I know there is an informal algorithm that can be used (and that people 
>> used to keep posting whenever I complained about complex typespecs), but 
>> I could never get it and just resorted to Cdecl instead. However the 
>> online Cdecl I used is no longer available, and I have to use trial and 
>> error.

Offhand, I can't figure out what algorithm I'm actually using. An
algorithm that works is to insert a dummy identifier in the first
location where the insertion would turn the type name into a valid
declaration for that identifier. If there is no such location, it isn't
a valid type name. If that identifier would identify an inline or
_Noreturn function, or an object with an alignment specification or an
initializer, then it isn't a valid type name. Otherwise, the type name
names the type that the identifier would have, if it were a declaration.

However, that algorithm requires a great deal of familiarity with C
declaration syntax - which is something that I have, but which Bartc and
most entry-level C programmers don't have.

While researching my answers for this thread, I noticed that 6.7.4p2
prohibits

	void _Noreturn (*noreturn_function)(void);

I was rather surprised by that - I would have thought that would be a
useful thing to allow.

[toc] | [prev] | [next] | [standalone]


#59444

FromMalcolm McLean <malcolm.mclean5@btinternet.com>
Date2015-04-02 05:28 -0700
Message-ID<b086a496-5695-4b46-b5ab-595bff8001cc@googlegroups.com>
In reply to#59416
On Thursday, April 2, 2015 at 12:29:57 AM UTC+1, James Kuyper wrote:
> 
> However, that algorithm requires a great deal of familiarity with C
> declaration syntax - which is something that I have, but which Bartc and
> most entry-level C programmers don't have.
> 
One of the faults of C is that the syntax for passing about multi-dimensional arrays,
and for declaring arrays of function pointers, is too complicated.
The answer is to avoid them if at all possible. That creates a feedback effect,
because people seldom see such constructs, and so are even less likely to
understand them.

[toc] | [prev] | [next] | [standalone]


#59417

FromBartc <bc@freeuk.com>
Date2015-04-02 00:37 +0100
Message-ID<mfhvei$8eo$1@dont-email.me>
In reply to#59415
On 02/04/2015 00:01, Barry Schwarz wrote:
> On Wed, 01 Apr 2015 22:55:50 +0100, Bartc <bc@freeuk.com> wrote:

>>>>     struct tag (*[5])(float)

>> I could try and tell you what the above means, but it will a guess.
>> Although I know the name goes just before the "*", because I tested my
>> guess with a compiler.
>
> I think you guessed wrong.  The name goes between the * and the [.

I got it right before but without the working example in front of me, I 
forgot which way around it was.

> Without the name, it specifies the type
>       array of five pointer-to-function
>
> Where each function pointed to
>            takes one argument of type float
>            returns a value of type struct tag
>
> With the name and a concluding ;, it would declare (and possibly
> define) an array object of that type.

I was way off the mark. I got that there was function taking a float 
argument involved, and an array of 5, a pointer, and a struct, but they 
weren't quite in the right order.

Anyway I'm never going to understand why any language would choose to 
have type declarations written in Chinese (as they might as well be).

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#59418

FromKeith Thompson <kst-u@mib.org>
Date2015-04-01 20:13 -0700
Message-ID<87bnj7i5nn.fsf@kst-u.example.com>
In reply to#59413
Bartc <bc@freeuk.com> writes:
> On 01/04/2015 22:40, James Kuyper wrote:
>> On 04/01/2015 04:17 PM, James Harris wrote:
>>> The type
>>>
>>>    struct tag (*[5])(float)
>>>
>>> appears in at least two draft C standards: for C89 and the n869 pdf. I
>>> find it hard to read because it has no identifier. I can see where an
>>> identifier can be placed but how is a programmer *supposed* to parse
>>> such a "type" when reading a standard? Is it as simple as knowing which
>>> symbols are prefixes and which would be suffixes?
>>
>> What you are talking about is described in 6.7.7p2:

[snip]

> But is a human reader supposed to do keep all this in mind? It should
> be instantly obvious!
>
> I know there is an informal algorithm that can be used (and that
> people used to keep posting whenever I complained about complex
> typespecs), but I could never get it and just resorted to Cdecl
> instead. However the online Cdecl I used is no longer available, and I
> have to use trial and error.

http://cdecl.org/ is up and running.  You should also be able to
insstall cdecl on your own system.  For most Linux systems, it should be
available as an installable package (`sudo apt-get install cdecl` or
equivalent).  If you're using Windows, I don't know how to install it,
but it should be possible; I vaguely recall that it's open-source.

Unfortunately for our current purpose, cdecl interprets declarations,
not types:

    $ cdecl
    Type `help' or `?' for help
    cdecl> explain struct tag (*[5])(float)
    syntax error
    cdecl> explain struct tag (*FOO[5])(float)
    declare FOO as array 5 of pointer to function (float) returning struct
    tag
    cdecl> 

So it can explain what the type is -- but only if you know where to
insert the identifier.

> I could try and tell you what the above means, but it will a
> guess. Although I know the name goes just before the "*", because I
> tested my guess with a compiler.

No, it goes after the identifier.  (And I don't think I can explain how
I figured that out.)

I agree with you that C's declaration syntax is unnecessarily obscure,
and I occasionally resort to cdecl myself.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#59433

FromBartc <bc@freeuk.com>
Date2015-04-02 10:30 +0100
Message-ID<mfj26g$4s7$1@dont-email.me>
In reply to#59418
On 02/04/2015 04:13, Keith Thompson wrote:
> Bartc <bc@freeuk.com> writes:

>However the online Cdecl I used is no longer available, and I
>> have to use trial and error.
>
> http://cdecl.org/ is up and running.

Thanks. I'd been using one at www.lemoda.net/c/cdecl.

>> I could try and tell you what the above means, but it will a
>> guess. Although I know the name goes just before the "*", because I
>> tested my guess with a compiler.
>
> No, it goes after the identifier.  (And I don't think I can explain how
> I figured that out.)

You mean, after the "*"...?

> I agree with you that C's declaration syntax is unnecessarily obscure,
> and I occasionally resort to cdecl myself.

Maybe it should be part of the language allowing you to optionally use 
English to declare types:

_cdeclare("name as array 5 of pointer to function (float) returning 
struct tag") ;

The compiler sees this as:

struct tag (*name[5])(float) ;

Another example:

typedef _cdeclare("T as array (N) of int");

Here I've had to introduce a (...) syntax when an array dimension is not 
a numeric literal. The contents of (...) are passed through unchanged. 
(I don't know how this would interact with the macro preprocessor; this 
is just an idea. Maybe _cdeclare could work on a series of tokens instead.)

The name can be optional so that _cdeclare() can be used in casts and 
for function parameters.

But you will still need an external Cdecl to make sense of existing 
declarations.

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#59494

FromKeith Thompson <kst-u@mib.org>
Date2015-04-02 15:18 -0700
Message-ID<87ego2gomr.fsf@kst-u.example.com>
In reply to#59433
Bartc <bc@freeuk.com> writes:
> On 02/04/2015 04:13, Keith Thompson wrote:
>> Bartc <bc@freeuk.com> writes:
[...]
>>> I could try and tell you what the above means, but it will a
>>> guess. Although I know the name goes just before the "*", because I
>>> tested my guess with a compiler.
>>
>> No, it goes after the identifier.  (And I don't think I can explain how
>> I figured that out.)
>
> You mean, after the "*"...?

Yes.

>> I agree with you that C's declaration syntax is unnecessarily obscure,
>> and I occasionally resort to cdecl myself.
>
> Maybe it should be part of the language allowing you to optionally use
> English to declare types:
>
> _cdeclare("name as array 5 of pointer to function (float) returning
> struct tag") ;
>
> The compiler sees this as:
>
> struct tag (*name[5])(float) ;

I dislike that idea, at least as a language feature.  We'd have to
define *rigorously* an English-like syntax for declarations, and it
would have to coexist with the existing syntax in the same language.

But I can see the convenience.  You could instead have a tool that
translates an English-like syntax into valid C declarations.  You could
then use that tool as part of your build process, to construct C source
files that you then compile.  It could retain the "English" version as
a comment.

For example, it could take as input:

    @ name as array 5 of pointer to function (float) returning struct tag

and produce as output:

    /* @ name as array 5 of pointer to function (float) returning struct tag */
    struct tag (*name[5])(float);

Personally I'd prefer to run the tool manually and include the generated
declarations in the C source file, which is then what's maintained.  The
automatically generated comments would still be useful.  Any non-C
syntax for declarations is going to annoy experienced C programmers --
much like the old
    #define BEGIN {
    #define END }
stuff.

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#59495

FromJohn Bode <jfbode1029@gmail.com>
Date2015-04-02 15:22 -0700
Message-ID<25a44dd7-ac43-46c7-9a0a-c5b3b86f63d5@googlegroups.com>
In reply to#59410
On Wednesday, April 1, 2015 at 3:21:08 PM UTC-5, James Harris wrote:
> The type
> 
>   struct tag (*[5])(float)
> 
> appears in at least two draft C standards: for C89 and the n869 pdf. I 
> find it hard to read because it has no identifier. I can see where an 
> identifier can be placed but how is a programmer *supposed* to parse 
> such a "type" when reading a standard? Is it as simple as knowing which 
> symbols are prefixes and which would be suffixes?
> 
> James

Yup. Given that we know '*' in a declaration is a unary operator that 
precedes the identifier and that '[]' is a postfix operator that follows the
identifier, we know that this declaration parses out as follows (you'll want
to read this with a fixed-width font):

                         - unnamed identifier
             [5]         - is a 5-element array of
            *[5]         - pointer to
           (*[5])(     ) - function taking
           (*[5])(     ) -    unnamed parameter
           (*[5])(float) -      of type float
struct tag (*[5])(float) - returning struct tag

In short, the type is an array of pointers to functions returning a struct.

Postfix operators like '[]' have higher precedence than unary operators like
'*', so *a[N] is an array of pointers, (*a)[N] is a pointer to an array,
*f() is a function returning a pointer, and (*f)() is a pointer to a 
function.  

Start with the leftmost identifier (or at least find where the leftmost
identifier would be, as above) and work your way out, applying those basic
rules as you go.  For function declarations, you get to apply them
recursively for each parameter.  

That's it.  That's all you need.  Be systematic about it, and hairy 
declarations get easier to parse (if no less eye-stabby).  

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web