Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #59410 > unrolled thread
| Started by | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| First post | 2015-04-01 21:17 +0100 |
| Last post | 2015-04-02 15:22 -0700 |
| Articles | 11 — 7 participants |
Back to article view | Back to comp.lang.c
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
| From | "James Harris" <james.harris.1@gmail.com> |
|---|---|
| Date | 2015-04-01 21:17 +0100 |
| Subject | struct 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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-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]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-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]
| From | Barry Schwarz <schwarzb@dqel.com> |
|---|---|
| Date | 2015-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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-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]
| From | Malcolm McLean <malcolm.mclean5@btinternet.com> |
|---|---|
| Date | 2015-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]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-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]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-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]
| From | John Bode <jfbode1029@gmail.com> |
|---|---|
| Date | 2015-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