Path: csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: Why does C allow structs to have a tag? Date: Mon, 07 Jun 2021 12:03:27 -0700 Organization: None to speak of Lines: 125 Message-ID: <8735ttsdj4.fsf@nosuchdomain.example.com> References: <0x4vI.109969$Ye1.83143@fx01.ams4> <20210606075302.305@kylheku.com> <3R9vI.65671$jM2.54125@fx02.ams4> <87v96qvdyx.fsf@nosuchdomain.example.com> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Injection-Info: reader02.eternal-september.org; posting-host="da0ef0006e1a2be3c584df7adb5e6866"; logging-data="6893"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/woU2sErrmxXmG9dAxkEYm" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:Lj1GiCh+6acTbKtLfPMSotmLHRA= sha1:6ARmjKhT40MJ/HmBgVmQIrT/txU= Xref: csiph.com comp.lang.c:161308 Manfred writes: > On 6/7/2021 12:13 AM, Keith Thompson wrote: >> Bart writes: >>> On 06/06/2021 20:12, David Brown wrote: >>>> On 06/06/2021 18:58, Manfred wrote: >>>>> On 6/6/2021 5:05 PM, Kaz Kylheku wrote: >>>>>>    typedef struct Nodetag Node; >>>>>> >>>>>>    struct Nodetag { >>>>>>      Nodetag *next; //  error: unknown type name ‘Nodetag’ >>>>>>    }; >>>>>> >>>>>> >>>>> >>>>> typedef struct Nodetag Node; >>>>> >>>>> struct Nodetag { >>>>>   int data; >>>>>   Node *next; >>>>> }; >>>> >>>> >>>> Or even: >>>> >>>> typedef struct Node Node; >>>> >>>> struct Node { >>>> int data; >>>> Node *next; >>>> }; >>>> >>>> There's no need for an extra name here. >>> >>> Unless you want to avoid any confusion. Since you can come across this: >>> >>> Node* A; >>> struct Node* B; >>> >>> Does one of those lines have a 'struct' missing, or does the other >>> have a 'struct' that shouldn't be there? >>> >>> The eye picks up such inconsistencies; it creates a distraction. >>> >>> Allowing two ways of denoting the same user-type is also sloppy. >> Which is a great argument for not bothering with the typedef: >> struct Node { >> int data; >> struct Node *next; >> }; >> struct Node obj; >> struct Node *ptr; >> // ... >> (Bart will argue that having to type "struct" again is a heavy >> burden. >> I will not respond.) > > Since I am no Bart, I am going to argue about that. > Not that's a heavy burden at all. My view is about consistent syntax > instead: > In C the canonical object declaration is: > > type_name object_name; > > One of the great strengths of the language is the possibility of > defining user defined types, by means of structs and unions (leaving > out typedefs that are aliases as you say) > From this perspective, after I have defined my type Foo as > struct Foo { int a; int b; }; > > I think it should be enough for the compiler to understand the correct > meaning when I write > Foo foo; Ideally, I agree. The reasons for requiring the struct keyword are historical. > Now, I know you say (strictly according to the standard) that the type > name is "struct Foo" instead of "Foo", however from the pure > syntactical perspective this is a combination of a keyword and a name, > so in C user defined type names are required to include a keyword in > their name; this is not consistent with other type names. A type name in C isn't just an identifer optionally preceded by keyword. It can be a sequence of keywords (unsigned long long int), or a combination of keywords and punctuation (void(*)(void)), and can even include expressions (unsigned char[2*x+y][time()%60]). The only way a C type name can be a single identifier is via a typedef -- a feature that was added to the language relatively late, and that has required parsers to be a bit more complicated. In the absence of typedefs, every type name in C has a syntactic marker to indicate whether it's an integer or floating-point type (one of several keywords), a pointer (*), a function (()), an array ([]), or a struct, union, or enum (struct, union, and enum keywords). Recall that C evolved from a language that didn't have types. The idea of *naming* types was added, and the idea of naming types with a single identifier was added even later. > I know that in practice it's no big deal, it's just something you have > to learn early on and you get used to it. > It's just that I am somewhat of a fan of language theory, syntax and > semantics. > That's why I like the C++ syntax for this considerably better. C++ still has all of C's syntactic quirks. I agree that being able to use the tag (what C calls a "class name") as a type name is an improvement -- and that it couldn't be adopted in C without breaking existing code. Given C's rules, my personal preference is to write out "struct foo" rather than creating a typedef -- unless the type is intended to be opaque, meaning that client code shouldn't know that it's a struct. (But if I were working on a project that had a convention of using typedefs, I'd follow that.) In C++, I just use the class name. > I think this is one matter that falls under the category of "hangover" > from obsolete compiler weaknesses, to use David's terms. > Obviously all of this is now carved in stone, so no one is expecting C > to change this "feature" - I'm just expressing my taste about it. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips Healthcare void Void(void) { Void(); } /* The recursive call of the void */