C and its many quirks - Page 1
Forum section: electronics / general

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 07:17:42 pm
content: Does anyone here ever use or advocate this kind of contrivance:Code:typedef struct {int age;int height;} Person;Seehere.I'm mainly asking about the idea of defining a type that is an array...

author: magic
author_rank: Super Contributor
timestamp: January 22, 2023, 07:29:26 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 07:17:42 pmNo

author: DiTBho
author_rank: Super Contributor
timestamp: January 22, 2023, 07:37:24 pm
content: No!

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 22, 2023, 07:48:36 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 07:17:42 pmSadly, with the example above, you are defining an array of struct, thus combining two concepts in one.You *did* mention that it was "mainly" about the type being an array, but this will inevitably make the topic go in all directions. Maybe it was intentional.As to your question, my answer is: it depends. I have nothing against this per se, although I almost never do that.But defining struct types, certainly. I always do.My general approach, when a given type contains a fixed-size array of something, is to encapsulate said array in a struct rather than making the array the type itself.I find it cleaner and more consistent (as for instance, you then have a type that can directly be assigned, contrary to an array.)But that's as with almost any other programming topic. You'll get many different answers, most with amazingly strong opinions.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 07:53:31 pm
content: Quote from: SiliconWizard on January 22, 2023, 07:48:36 pmNo, theintentionis as stated, to gather opinions on that kind of use of typedef, defining types that are themselves arrays. In this case 'Person' represents an array, instances of 'Person' are three element arrays.

author: gf
author_rank: Super Contributor
timestamp: January 22, 2023, 08:18:56 pm
content: Why should an array type not have a typedef'ed name, too? But for clarity I'd rather writeCode:struct {int age;int height;} Person;typedef struct Person PersonTriple;PersonTriple myTriple;Unfortunately there is still the limitation that objects of type PersonTriple cannot be assigned, since arrays cannot be assigned.As SiliconWizard said, this can be addressed by wrapping the array by a struct, or in C++ I could use std::array instead:Code:struct {int age;int height;} Person;typedef std:array<Person, 3> PersonTriple;PersonTriple myTriple;

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 08:28:47 pm
content: Quote from: gf on January 22, 2023, 08:18:56 pmThe thing I dislike about this that 'Person' as a type name does not convey the fact it is an array. It also places the bound specifier after the type name, whereas ordinarily in C we put array bounds after the variable being declared, if C did this:Code:uint8_t counters;it would be more consistent, but we can't do that in C.This might seem pedantic but I'm currently considering this as part of my design for IPL, whether to allow it or not. If not, why? if so, why?

author: JPortici
author_rank: Super Contributor
timestamp: January 22, 2023, 08:45:41 pm
content: Quote from: SiliconWizard on January 22, 2023, 07:48:36 pmSame.Defining a type that is actually an array is.. oof.

author: gf
author_rank: Super Contributor
timestamp: January 22, 2023, 08:47:29 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 08:28:47 pmJust call the type name 'PersonArray', and I think it becomes self-explanatory.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 22, 2023, 08:58:06 pm
content: Quote from: gf on January 22, 2023, 08:47:29 pmWell, the argument is just the same as with people not typedef'ing structs as it doesn't convey the fact they are structs (and this is why I pointed out that by mixing the two in one typedef, the OP was sure going to trigger strong reactions - double the reaction if you will!)By that reasoning, we would remove type definitions altogether. (Yuck.) Way to run in circles with decades of computer science.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 09:01:04 pm
content: Quote from: gf on January 22, 2023, 08:47:29 pmBut now there's no way to declare asingle'Person' structure, the language is not helping us now but creating scenarios that are potentially troublesome, creating a situation where we have to fight it or create another typedef that's a copy of the first typedef's structure,

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 09:14:01 pm
content: I'm trying to find out how Ada lets you declare a 'record' that itself contains other record definitions, I'm curious about the grammar...

author: gf
author_rank: Super Contributor
timestamp: January 22, 2023, 09:14:56 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 09:01:04 pmWhy not? See again my example:Code:struct {int age;int height;} Person;typedef struct Person PersonTriple;Or if you prefer to use a type name instead of a struct name, thenCode:typedef struct {int age;int height;} Person;typedef Person PersonTriple;'Person' (or 'struct Person') refers to the type of a single person struct, and 'PersonTriple' is the type of the array.

author: magic
author_rank: Super Contributor
timestamp: January 22, 2023, 09:18:30 pm
content: Quote from: gf on January 22, 2023, 08:47:29 pmFTFY.And ditto for *Person and so on. Which is whyQuote from: magic on January 22, 2023, 07:29:26 pm

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 22, 2023, 09:24:27 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 09:14:01 pmPretty much all high-level languages allow this, all the way back to decades ago. I'm not sure I get what there is to find out?

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 09:25:01 pm
content: Quote from: gf on January 22, 2023, 09:14:56 pmWhy not? As I said if a type has been declare like this:Code:typedef struct {int age;int height;} Person;Then there's no way to declare a single struct instance. Yes it's easy to do IF we declare it differently. By letting us declare an array type, by allowing that, it leads to situations where we have to fight the language.If a typedef could never be an array then the problem of being sometimes unable to declare a single instance can never happen, this is an argument for not allowing this in a language that lets is define types - IMHO.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 09:27:34 pm
content: Quote from: SiliconWizard on January 22, 2023, 09:24:27 pmAn example, I want an example. I've found examples of user defined types that contain members of other user defined types, I want to see how one can declare a user defined record type that has embedded records, not types that are records but the full record definition itself, how does one nest recorddefinitionsin Ada?

author: newbrain
author_rank: Super Contributor
timestamp: January 22, 2023, 09:30:36 pm
content: Quote from: Sherlock Holmes, snipped by newbrain on January 22, 2023, 08:28:47 pmIt's not pedantic, but shows a slightly superficial knowledge of some C syntax peculiarities.Just remember that typedef (apart from NOT defining a new type, but only an alias) is - for syntactic convenience - a storage class specifier.In this way, you can typedef something exactly as you would declare a variable of that type.I like it, as I find it easier to parse, but I'm heavily biased.Ref ISO/IEC 9899:2011: "6.7.8 Type definitions", §3 and "6.7.1 Storage-class specifiers", §5

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 09:31:55 pm
content: Here's the Ada question, how does one write this in AdaCode:struct Info{char name;int age;struct address{char area_name;int house_no;char district;};};

author: gf
author_rank: Super Contributor
timestamp: January 22, 2023, 10:04:59 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 09:25:01 pmThis is not limited to arrays. You can generally not refer to anonymous (unnamed) types.In the following example you cannot refer to to the inner struct type either:Code:struct S {struct {int age;int height;} inner;int x;};Just declare it differently and give a name to each type you want to reference later. What's the problem?

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: January 22, 2023, 10:10:05 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 07:17:42 pmDefining a typename alias that is an array is perfectly good as long as it implements some sort of fairly complete data type concept. For example,Code:typedef int Vector3D;struct Point2D { int x, y; };typedef struct Point2D Segment;Nothing wrong with it. The reasoning here is no different than defining any other alias typename. Arrays are aggregates just like structs are aggregates. No need to impose any special treatment onto arrays. With one exception though: with arrays one just have to remember that naked objects of that type are not copyable. You can't assign them, you can't pass/return them by value.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 10:12:47 pm
content: Quote from: gf on January 22, 2023, 10:04:59 pmIt's not a problem but a question raised in my OP. The question really boils down to what good reason is there to support this:Code:typedef struct {int age;int height;} Person;As you and others have shown we can avoid this by doing it differently, so it seems there no good reason to support this in a language in the first place. If it is used it carries the risks of being unable to declare a single element of the structure (without all kinds of fall out).So I don't have a "problem" I think I have my answer now.

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: January 22, 2023, 10:19:09 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 10:12:47 pmWhat is "this" in this case? Type alias for an array? Tagless struct type? Combined declaration for a type alias and a struct type? There are to many things piled up in the above to figure out what specifically you mean by "this".The above is a syntactically valid construct, if only a bit too convoluted. The construct itself is perfectly useful in many contexts. There are no "quirks" in it.The potential for abuse is there (as it is there in virtually every feature if the language), but interpreting the "abusive" code does not require any additional implementational effort from the compiler. It comes for free. The language does not refuse and does not need to refuse to support something on purely cosmetic grounds (e.g. when it just "looks too convoluted").

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 10:24:40 pm
content: Quote from: TheCalligrapher on January 22, 2023, 10:10:05 pmThat's not a good counter example because 'int' exists as a distinct type already apart from the Vector3D typedef.I'm speaking of the case where an array of some unnamed struct X is defined in a typedef named Y as an array of say 3 elements. In this case there's no way to declare 1, 2, 4, 5 etc arrays of that unnamed struct X should the need ever arise.There are other ways to code it, my position is that the language should not allow us to do it that bad way, it's not a good or helpful feature, what it achieves can be achieved in other far safer ways.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 10:29:48 pm
content: Quote from: TheCalligrapher on January 22, 2023, 10:19:09 pm"this" is a typedef array for an unnamed struct. Should we ever need 1, 2, 4, 5 elements in some other part of the code one day, then we cannot unless we do one of these:1. Change the typedef and change every declaration of it to to now be an array.2. Copy/paste the structure into another typedef that represents a single instance of the struct.Therefore allowing the construct in the first place is a mistake IMHO, it serves no purpose, there are other ways to do what's intended there without needing to do 1. or 2.You claim its useful, how? show me an example of where it is more useful than some of the other options for doing this?Code:typedef struct {int age;int height;} Person;Could be:Code:typedef struct {int age;int height;} Person;typedef struct {Person people;} ThreePersonTeam;For example. If that was the ONLY way to do it, what problems arise? what would one lose by disallowing the first approach?From what I can see there'sno downsideto disallowing the definition of typedef arrays, so in a new language it would be wise to do that, disallow the capability.

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: January 22, 2023, 10:31:32 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 10:24:40 pmIf that is your "this", then I agree with you 100%. Defining a tagless/nameless struct type, as shown in your example, definitely does not not look like a good idea. I don't like the fact that I have no way to refer to array element type further down in the code.To be pedantic, in a pinch it would still possible to refer to the array element type using `decltype` in C++ and `typeof` in the upcoming C23. But I'd personally just give that struct type a tag.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 22, 2023, 10:42:15 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 09:31:55 pmAnd bam, that's again a particular case which was absolutely not obvious in your original question. A record inside a record? No problem. But what you actually meant was: an anonymous record. How are we supposed to guess?Anonymous struct/union members in C have been a GCC extension for a long time, but are non-standard. The standard way was to give the member a name. Just like with other languages.So instead of something like 'info.house_no' directly, you would have to give the address member a name (eg, 'address'), and access it as 'info.address.house_no'. Same in Ada. Ada has variant records (Pascal had them too IIRC) though, and you can get the somewhat equivalent of "anonymous union members inside a struct" in C.Anonymous stuct/union members can be elegant in some cases, but one should not abuse them IMO.And I think - but I'm not 100% sure - they have made their way in the C standard in C23. But that has to be checked, surely. (Was it in C11 even?)

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 10:42:31 pm
content: Quote from: TheCalligrapher on January 22, 2023, 10:31:32 pmYes that's all I'm saying here, if designing a new language that had the ability to do something akin to C's typedef, it would be wise to disallow that kind of use.

author: DiTBho
author_rank: Super Contributor
timestamp: January 22, 2023, 10:44:50 pm
content: Quote from: JPortici on January 22, 2023, 08:45:41 pmYupthe only good one, the most close one, is thisCode:typedef char_t ans_test_body_t;typedef ans_test_body_t ans_test_t;ans_test_t ans_test={ "failure", "success"};...result = do_test(i0);printf("test-%04lu: %s\n", i0, ans_test[result);(my-c)

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 10:47:06 pm
content: Quote from: SiliconWizard on January 22, 2023, 10:42:15 pmVery well, how does Ada do this then, I did not mean to make then annonymous.Code:struct info {char name;int age;struct address {char area_name;int house_no;char district;} Address;} Info;I can refer to "house_no" so long as I qualify the reference to it withInfo.Address. But how can one do that in Ada, nest structure declarations in that way?That'sthe question I'm struggling to find an answer too...

author: newbrain
author_rank: Super Contributor
timestamp: January 22, 2023, 11:10:00 pm
content: Quote from: SiliconWizard, abundantly abridged on January 22, 2023, 10:42:15 pmThey are in fact in C11, "6.7.2.1 Structure and union specifiers", §13:Quote

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 11:15:15 pm
content: The Ada question is interesting to me because Idothink this kind of array definition is fine:Code:struct info {char name;int age;struct address {char area_name;int house_no;char district;} Address;} Info;This is a struct with a storage layout and if that storage layout contains four contiguous 'Address' elements then that's fine, these aren't type definitions.I'm curious as to how Ada expresses this or if it forces us to define types and construct the structure in terms of those types, like that's the only way to do it...

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 11:17:57 pm
content: Quote from: newbrain on January 22, 2023, 11:10:00 pmWhat's rather bothersome about C is the way we have a name in two parts of the declaration:Code:struct info {char name;int age;struct address {char area_name;int house_no;char district;} Address;} Info;Here we see a thing called 'address' and another thing called 'Address', it's a very odd syntax indeed.

author: cfbsoftware
author_rank: Regular Contributor
timestamp: January 22, 2023, 11:27:30 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 10:47:06 pmOberon is similar to Ada for these types of declarations. In Oberon this is written as:Code:TYPEInfo = RECORDname: ARRAY 30 OF CHAR;age: INTEGER;address:RECORDareaName: ARRAY 39 OF CHAR;houseNo: INTEGER;district: ARRAY 39 OF CHAR;END;END;However, I would be more likely (depending on the exact requirements) to write this as:Code:TYPEName = ARRAY 30 OF CHAR;Location = ARRAY 39 OF CHAR;Address = RECORDhouseNo: INTEGER;areaName, district: Location;END;Person = RECORDname: Name;age: INTEGER;address: Address;END;In Oberonentire recordscan be assigned so, given these declarations you could write:Code:VARtwin1, twin2: Person;......twin2 := twin1;twin1.name := "John Smith";twin2.name := "Jane Smith";......

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: January 22, 2023, 11:34:07 pm
content: Quote from: newbrain on January 22, 2023, 11:10:00 pmThey are. But they still require the nested struct declaration to be tagless. The original OP's declaration is invalid in C, regardless of how you slice it.

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: January 22, 2023, 11:37:05 pm
content: Quote from: Sherlock Holmes on January 22, 2023, 11:17:57 pmIt's a type name (a tag) and a variable name. There's nothing unusual in the fact that you have to name the two separately. In any programming language, I'd say. Types are types, variables are variables.The only thing that might be seen as odd here is the fact that you decided to lump them up into a single declaration. But that's entirely of your doing. You didn't have to do it that way.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 22, 2023, 11:45:26 pm
content: Quote from: TheCalligrapher on January 22, 2023, 11:37:05 pmYes. Actually, I'm not sure I fully understand the consistency of everything here.The OP seems to say he doesn't want to allow declarations of hierarchical types directly, yet shows an example of a nested hierarchical declaration. The consistency eludes me.

author: gf
author_rank: Super Contributor
timestamp: January 22, 2023, 11:46:34 pm
content: Quote from: TheCalligrapher on January 22, 2023, 11:37:05 pmWhat's also special in C is the differentiation between struct/union names (which always need to be prefixed with 'struct' or 'union') and type names (declared via typedef). In C++, OTOH,struct S {...};also declares a type name 'S' which can be referenced directly, without 'struct' prefix.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 22, 2023, 11:52:16 pm
content: Quote from: cfbsoftware on January 22, 2023, 11:27:30 pmThank you this is most interesting.Here is the current syntax for "defining a new type" (or rather "alias" might be the better term).Code:type outer structure;cpu_id bin(31);inner structure;cpu_mode bin(31);cpu_rev bin(15);large as Header;flag_table structure;root pointer;depth fixed bin(15);structure structure;goofy pointer;end;end;label string(64);end;owner string(64);speed(100) as baud_rates;counter string(32);end;This works, and it and several complex variants now parse without issue and build the expected parse tree.I can see that making say 'flag_table' an array, is entirely legitimate, it is describing the layout of some structured storage, so an array of members be they scalar fields or structures is entirely sensible.The conceptual concern I have is that 'outer' (the main structure itself) is not itself a structure but a 'type' name and so allowing that to be subscripted is a bad idea for the reasons I mention above.So its just niggling me that the type is defined as "outer structure" and embedded struct instance like "flag_table structure" use the same notation, but then again the former is prefixed by "type".Furthermore I am inclined to disallow the declaration of structure instances like this, to only allow a "type" or "alias" to be defined this way and then one must use that alias to declare instances. But I don't want to impose that rule when inserting sub structures inside some larger structure, so I don't want to force the developer to define a "type" for an embedded structure if they don't want to, only for the outermost structure.So I'm trying to rationalize all this in a way that is completely free of contrived syntactic rules...By the way the "nameasothername" is the way we declare "name"asbeing of user defined type "othername".

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 23, 2023, 12:02:55 am
content: Quote from: TheCalligrapher on January 22, 2023, 11:34:07 pmThis is valid C:Code:typedef struct {int age;int height;} Person;See this slightly later post for proof of that.https://www.eevblog.com/forum/programming/c-and-its-many-oddities/msg4654957/#msg4654957

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 23, 2023, 12:06:30 am
content: Quote from: TheCalligrapher on January 22, 2023, 11:37:05 pmOh I understand it, it's just a very contrived syntax, what I mean it could have been simpler.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 23, 2023, 12:10:29 am
content: Quote from: SiliconWizard on January 22, 2023, 11:45:26 pmNot at all, where did I say I "don't want to allow declarations of hierarchical types directly"? which post areyou interpretingthat way?All I've said is that in a language that lets you define an alias/typedef for something else, there should be no scope for that alias/typedef to inherentlybean array. The reasons are expounded upon above.

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: January 23, 2023, 01:02:26 am
content: Quote from: Sherlock Holmes on January 23, 2023, 12:02:55 amYes, this is valid. I'm not arguing with that.I was referring to another "original" declaration: the one in the sub-discussion about anonymous structs. This one:Code:struct Info{char name;int age;struct address{char area_name;int house_no;char district;};};This is not valid C.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 23, 2023, 04:42:22 pm
content: Well regarding this whole subject of structures and typedefs, I've settled on IPL having a slightly simpler approach.Basically one cannot declare a structure using structure declaration syntax. That structure declaration syntax can ONLY be used to define a "type", e.g.Code:type flag_table structure;root pointer;depth fixed bin(15);subunit structure;goofy pointer;end;end;To declare a structure instance, one must use and can only use, the type's name:Code:dcl my_data as flag_table;The above could also be:Code:type Subunit structure;goofy pointer;end;type flag_table structure;root pointer;depth fixed bin(15);subunit as Subunit;end;Same goes for "enum" one must define an enum using "type" and then instances of it using that type's name.I see nothing useful in being able to declare a struct instance explicitly with structure syntax, when we can define types using structure syntax and declare instances of said type, nothing useful about that IMHO.This might seem like much ado about nothing, but it's part of the endeavor to reduce language "noise", eliminate redundant concepts and code structures.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 23, 2023, 05:03:39 pm
content: Quote from: cfbsoftware on January 22, 2023, 11:27:30 pmIn your second example of a 'TYPE' it seems thatthattype has no name, whereas the first one has a name of 'Info', so these are alternative ways of declaring a structure instance?Yes structure to structure assignments are important, C has that too. In PL/I there was an assignment option of 'by name' that allowed one type of structure to be assigned from another type but only where the member names match.This might be something I want to expand upon, but I don't know if it is ultimately helpful, the 'by name' seems to have its roots in older mainframe COBOL days where data was always processed by consuming files, sequences or structured records. Some of the strictures I saw used in PL/I in the 80s were sometimes very big indeed, and might have even been designed with 'by name' in mind.The problem I have with 'by name' is that I can imagine scenarios where someone innocently adds some new member to some structure or renames some member, and all of a sudden some 'by name' assignment start to do more than it used to, in a way that was unexpected by the person making the change.Perhaps a richer syntax might work:Code:record = master_record by name (address, phone_numbers);This way the members impacted by the assignment are clearly visible. But that more or less boils down to:Code:record.address = master_record.address;record.phone_numbers = master_record.phone_numbers;So I was never a fan of 'by name'.

author: Sherlock Holmes
author_rank: Frequent Contributor
timestamp: January 23, 2023, 05:18:01 pm
content: Actually just perusing the ANSI X3.74-1987 standard, there is no 'by name' option, it was basically part of old "full PL/I".

author: cfbsoftware
author_rank: Regular Contributor
timestamp: January 24, 2023, 10:17:17 pm
content: Quote from: Sherlock Holmes on January 23, 2023, 05:03:39 pmThe type in my second exampledoeshave a name. I renamed it to Person from Info - just apersonalpreference