Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: How to use a struct with qsort()? Date: Wed, 23 Oct 2019 13:51:12 -0700 Organization: None to speak of Lines: 115 Message-ID: References: <06add10e-1e30-4741-a20c-ff56363733fe@googlegroups.com> <865zkfhbn8.fsf@linuxsc.com> <4w_rF.736155$CO2.65319@fx30.am4> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="64ad45cb853e029c5cbfc6eca5dfb10d"; logging-data="20022"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18iCiCaePKzte9gXoO0Nweo" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:fjPxKpSqK5LTny3BBnSgZzcDUj4= sha1:ZBFKJZLLH9itNQAylWe07RGH3v8= Xref: csiph.com comp.lang.c:147178 Bart writes: > On 23/10/2019 13:47, Tim Rentsch wrote: >> Keith Thompson writes: >> >>> Bart writes: >>> >>>> [...] Use a typedef to give the struct its own name, so that you >>>> don't have to write 'struct words' everywhere, eg: >>>> >>>> typedef struct {char *word; double wordpf;} Words; >>>> >>>> Now you can write >>>> >>>> Words **wordrec = NULL; >>>> >>>> or sizeof(Words) etc. >>> >>> That's a perfectly valid choice. It has the advantage that the >>> name of the type is a single identifier. >>> >>> Personally, though, I prefer to refer to the type as "struct >>> whatever" rather than inventing a new name for it. My point of >>> view is that if you define a struct with a tag, it already has a >>> perfectly good name. [...] >> >> If a struct is defined with a tag, there is no doubt that the >> type already has a name. Whether that name is a perfectly good >> name is another question altogether. > > It doesn't have a name that is a pure identifier, such as T. You have to > refer to it by the composite 'struct T'. Correct. And the types `int*` and `char[20]` also don't have names that are pure identifiers. Most C type names are not pure identifiers. Most of them are keywords (int), or sequences of keywords (unsigned long), or various combinations of keywords, identifiers, and punctuation symbols (char **). In the absence of typedefs and macros, C type names are *never* pure identifiers. > And given 'struct T', that T could exist in the same scope as an > unrelated type 'T'. Further, you can choose to do one of: > > struct T T; > > or: > > typedef struct T T; > > or both: > > struct T T; > typedef struct U U; > > So struct T and the variable T have the same name, sort of; and struct U > and the type U have the same name, sort of, and here can be used > interchangeably. Yes, you can create a mess if you use the identifiers "T" and "U" for everything. That's why it's a good idea to use more descriptive names. The problem in your examples isn't the "struct" keyword, it's the short and non-descriptive names you chose. (Names like "T" are fine for non-specific examples, but are rarely a good idea in real life.) > This is why it might be best to forget the possibility of struct tags > altogether, and always define a typedef for a struct. That requires a little extra work if a struct contains a pointer to itself. For example, you can have the typedef *before* the full struct definition: typedef struct node node; struct node { int data; node *next; }; Or you can refer to the type as "struct node" inside its definition and refer to the typedef elsewhere: typedef struct node { int data; struct node *next; } node; > Then the name of the struct type will be a regular identifier like other > user types and the tag cannot clash with either other user types or > variables Again, most other user types don't have names that are single identifiers, unless you create such names explicitly. You can use typedef to create such names if you like, and a lot of programmers do so. I'm not saying there's anything wrong with that. If you think it's a great advantage for your types to have names that are single identifiers, I'm not even saying you're wrong. It's just not my preference. And if you're going to be reading C code written by others, you'll need to cope with both styles. > It also helps to make the type more opaque, which in turn means you can > change the underlying type without having to change 100s of 'struct T' > to 'struct T*' or 'U'. Typedefs are appropriate for types that actually need to be opaque (see FILE, for example). But if code that uses your type is going to be referring to member names, there's no point in trying to hide the fact that it's a structure. (If you change it from a struct to a struct pointer, you'll have to change "." to "->" in client code, and likely make other changes.) -- Keith Thompson (The_Other_Keith) kst-u@mib.org Will write code for food. void Void(void) { Void(); } /* The recursive call of the void */