EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: Sherlock Holmes on January 22, 2023, 07:17:42 pm

Title: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 07:17:42 pm
Does anyone here ever use or advocate this kind of contrivance:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

See here (https://stackoverflow.com/questions/8041826/assigning-array-of-structs-to-a-typedef-struct).

I'm mainly asking about the idea of defining a type that is an array...
Title: Re: C and its many quirks
Post by: magic on January 22, 2023, 07:29:26 pm
Does anyone here ever use or advocate this kind of contrivance:

Code: [Select]
typedef

No >:(
Title: Re: C and its many quirks
Post by: DiTBho on January 22, 2023, 07:37:24 pm
No!
Title: Re: C and its many quirks
Post by: SiliconWizard on January 22, 2023, 07:48:36 pm
Does anyone here ever use or advocate this kind of contrivance:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

See here (https://stackoverflow.com/questions/8041826/assigning-array-of-structs-to-a-typedef-struct).

I'm mainly asking about the idea of defining a type that is an array...

Sadly, 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.
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 07:53:31 pm
Does anyone here ever use or advocate this kind of contrivance:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

See here (https://stackoverflow.com/questions/8041826/assigning-array-of-structs-to-a-typedef-struct).

I'm mainly asking about the idea of defining a type that is an array...

Sadly, 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.

No, the intention is 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.

[attachimg=1]



Title: Re: C and its many quirks
Post by: gf on January 22, 2023, 08:18:56 pm
Why should an array type not have a typedef'ed name, too? But for clarity I'd rather write

Code: [Select]
struct {
    int age;
    int height;
} Person;

typedef struct Person PersonTriple[3];

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: [Select]
struct {
    int age;
    int height;
} Person;

typedef std:array<Person, 3> PersonTriple;

PersonTriple myTriple;
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 08:28:47 pm
Why should an array type not have a typedef'ed name, too? But for clarity I'd rather write

Code: [Select]
struct {
    int age;
    int height;
} Person;

typedef struct Person PersonTriple[3];

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: [Select]
struct {
    int age;
    int height;
} Person;

typedef std:array<Person, 3> PersonTriple;

PersonTriple myTriple;

The 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: [Select]
uint8_t[4]   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?



Title: Re: C and its many quirks
Post by: JPortici on January 22, 2023, 08:45:41 pm
Does anyone here ever use or advocate this kind of contrivance:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

See here (https://stackoverflow.com/questions/8041826/assigning-array-of-structs-to-a-typedef-struct).

I'm mainly asking about the idea of defining a type that is an array...

Sadly, 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.

Same.
Defining a type that is actually an array is.. oof.
Title: Re: C and its many quirks
Post by: gf on January 22, 2023, 08:47:29 pm
The thing I dislike about this that 'Person' as a type name does not convey the fact it is an array.

Just call the type name 'PersonArray', and I think it becomes self-explanatory.
Title: Re: C and its many quirks
Post by: SiliconWizard on January 22, 2023, 08:58:06 pm
The thing I dislike about this that 'Person' as a type name does not convey the fact it is an array.

Just call the type name 'PersonArray', and I think it becomes self-explanatory.

Well, 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! ;D )

By that reasoning, we would remove type definitions altogether. (Yuck.) Way to run in circles with decades of computer science.

Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 09:01:04 pm
The thing I dislike about this that 'Person' as a type name does not convey the fact it is an array.

Just call the type name 'PersonArray', and I think it becomes self-explanatory.

But now there's no way to declare a single '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,

Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 09:14:01 pm
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...
Title: Re: C and its many quirks
Post by: gf on January 22, 2023, 09:14:56 pm
But now there's no way to declare a single 'Person' structure

Why not? See again my example:

Code: [Select]
struct {
    int age;
    int height;
} Person;

typedef struct Person PersonTriple[3];

Or if you prefer to use a type name instead of a struct name, then

Code: [Select]
typedef struct {
    int age;
    int height;
} Person;

typedef Person PersonTriple[3];

'Person' (or 'struct Person') refers to the type of a single person struct, and 'PersonTriple' is the type of the array.

Title: Re: C and its many quirks
Post by: magic on January 22, 2023, 09:18:30 pm
Just call the type name Person[3], and I think it becomes self-explanatory.
FTFY.

And ditto for *Person and so on. Which is why
Does anyone here ever use or advocate this kind of contrivance:

Code: [Select]
typedef

No >:(
Title: Re: C and its many quirks
Post by: SiliconWizard on January 22, 2023, 09:24:27 pm
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...

Pretty 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?
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 09:25:01 pm
But now there's no way to declare a single 'Person' structure

Why not? See again my example:

Code: [Select]
struct {
    int age;
    int height;
} Person;

typedef struct Person PersonTriple[3];

Or if you prefer to use a type name instead of a struct name, then

Code: [Select]
typedef struct {
    int age;
    int height;
} Person;

typedef Person PersonTriple[3];

'Person' (or 'struct Person') refers to the type of a single person struct, and 'PersonTriple' is the type of the array.

Why not? As I said if a type has been declare like this:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

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.
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 09:27:34 pm
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...

Pretty 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?

An 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 record definitions in Ada?
Title: Re: C and its many quirks
Post by: newbrain on January 22, 2023, 09:30:36 pm
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:
[...]
This might seem pedantic
It'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
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 09:31:55 pm
Here's the Ada question, how does one write this in Ada

Code: [Select]
    struct Info{
        char name[30];
        int age;
        struct address{
            char area_name[39];
            int house_no;
            char district[39];
        };
    };
Title: Re: C and its many quirks
Post by: gf on January 22, 2023, 10:04:59 pm
As I said if a type has been declare like this:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

Then there's no way to declare a single struct instance.

This 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: [Select]
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?
Title: Re: C and its many quirks
Post by: TheCalligrapher on January 22, 2023, 10:10:05 pm
Does anyone here ever use or advocate this kind of contrivance:
I'm mainly asking about the idea of defining a type that is an array...

Defining 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: [Select]
typedef int Vector3D[3];

struct Point2D { int x, y; };
typedef struct Point2D Segment[2];

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.
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 10:12:47 pm
As I said if a type has been declare like this:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

Then there's no way to declare a single struct instance.

This 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: [Select]
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?

It'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: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

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.

Title: Re: C and its many quirks
Post by: TheCalligrapher on January 22, 2023, 10:19:09 pm
It'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: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

What 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").
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 10:24:40 pm
Does anyone here ever use or advocate this kind of contrivance:
I'm mainly asking about the idea of defining a type that is an array...

Defining 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: [Select]
typedef int Vector3D[3];

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 values of that type are not copyable.

That'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.


 

Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 10:29:48 pm
It'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: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

What 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").

"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: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

Could be:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person;

typedef struct {
   Person people[3];
} 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's no downside to disallowing the definition of typedef arrays, so in a new language it would be wise to do that, disallow the capability.


Title: Re: C and its many quirks
Post by: TheCalligrapher on January 22, 2023, 10:31:32 pm
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.

If 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.
Title: Re: C and its many quirks
Post by: SiliconWizard on January 22, 2023, 10:42:15 pm
Here's the Ada question, how does one write this in Ada

Code: [Select]
    struct Info{
        char name[30];
        int age;
        struct address{
            char area_name[39];
            int house_no;
            char district[39];
        };
    };

And 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?)
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 10:42:31 pm
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.

If 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.

Yes 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.
Title: Re: C and its many quirks
Post by: DiTBho on January 22, 2023, 10:44:50 pm
Defining a type that is actually an array is.. oof.

Yup

the only good one, the most close one, is this

Code: [Select]
typedef char_t ans_test_body_t[8];
typedef ans_test_body_t ans_test_t[2];

ans_test_t ans_test={ "failure", "success"};

...

result = do_test(i0);
printf("test-%04lu: %s\n", i0, ans_test[result);
(my-c)
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 10:47:06 pm
Here's the Ada question, how does one write this in Ada

Code: [Select]
    struct Info{
        char name[30];
        int age;
        struct address{
            char area_name[39];
            int house_no;
            char district[39];
        };
    };

And 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?)

Very well, how does Ada do this then, I did not mean to make then annonymous.

Code: [Select]
struct info {
char name[30];
int age;
struct address {
char area_name[39];
int house_no;
char district[39];
} Address;
} Info;

I can refer to "house_no" so long as I qualify the reference to it with Info.Address. But how can one do that in Ada, nest structure declarations in that way? That's the question I'm struggling to find an answer too...

Title: Re: C and its many quirks
Post by: newbrain on January 22, 2023, 11:10:00 pm
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.
[...]
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?)
They are in fact in C11, "6.7.2.1 Structure and union specifiers", §13:
Quote
An unnamed member whose type specifier is a structure specifier with no tag is called an
anonymous structure; an unnamed member whose type specifier is a union specifier with
no tag is called an anonymous union. The members of an anonymous structure or union
are considered to be members of the containing structure or union. This applies
recursively if the containing structure or union is also anonymous.
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 11:15:15 pm
The Ada question is interesting to me because I do think this kind of array definition is fine:

Code: [Select]
struct info {
char name[30];
int age;
struct address {
char area_name[39];
int house_no;
char district[39];
} Address[4];
} 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...
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 11:17:57 pm
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.
[...]
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?)
They are in fact in C11, "6.7.2.1 Structure and union specifiers", §13:
Quote
An unnamed member whose type specifier is a structure specifier with no tag is called an
anonymous structure; an unnamed member whose type specifier is a union specifier with
no tag is called an anonymous union. The members of an anonymous structure or union
are considered to be members of the containing structure or union. This applies
recursively if the containing structure or union is also anonymous.

What's rather bothersome about C is the way we have a name in two parts of the declaration:

Code: [Select]
struct info {
char name[30];
int age;
struct address {
char area_name[39];
int house_no;
char district[39];
} Address;
} Info;

Here we see a thing called 'address' and another thing called 'Address', it's a very odd syntax indeed.

Title: Re: C and its many quirks
Post by: cfbsoftware on January 22, 2023, 11:27:30 pm
Code: [Select]
    struct Info{
        char name[30];
        int age;
        struct address{
            char area_name[39];
            int house_no;
            char district[39];
        };
    };

I can refer to "house_no" so long as I qualify the reference to it with Info.Address. But how can one do that in Ada, nest structure declarations in that way? That's the question I'm struggling to find an answer too...

Oberon is similar to Ada for these types of declarations. In Oberon this is written as:

Code: [Select]
TYPE
  Info = RECORD
    name: ARRAY 30 OF CHAR;
    age: INTEGER;
    address:
      RECORD
        areaName: 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: [Select]
TYPE
  Name = ARRAY 30 OF CHAR;
  Location = ARRAY 39 OF CHAR;

  Address = RECORD
    houseNo: INTEGER;
    areaName, district: Location;
  END;
   
  Person = RECORD
    name: Name;
    age: INTEGER;
    address: Address;
  END;
In Oberon entire records can be assigned so, given these declarations you could write:

Code: [Select]
VAR
  twin1, twin2: Person;
 
...
...
  twin2 := twin1;
  twin1.name := "John Smith";
  twin2.name := "Jane Smith";
...
...
Title: Re: C and its many quirks
Post by: TheCalligrapher on January 22, 2023, 11:34:07 pm
They are in fact in C11, "6.7.2.1 Structure and union specifiers", §13:
Quote
An unnamed member whose type specifier is a structure specifier with no tag is called an
anonymous structure; an unnamed member whose type specifier is a union specifier with
no tag is called an anonymous union. The members of an anonymous structure or union
are considered to be members of the containing structure or union. This applies
recursively if the containing structure or union is also anonymous.

They 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.
Title: Re: C and its many quirks
Post by: TheCalligrapher on January 22, 2023, 11:37:05 pm
Here we see a thing called 'address' and another thing called 'Address', it's a very odd syntax indeed.

It'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.
Title: Re: C and its many quirks
Post by: SiliconWizard on January 22, 2023, 11:45:26 pm
Here we see a thing called 'address' and another thing called 'Address', it's a very odd syntax indeed.

It'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.

Yes. 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.
Title: Re: C and its many quirks
Post by: gf on January 22, 2023, 11:46:34 pm
Here we see a thing called 'address' and another thing called 'Address', it's a very odd syntax indeed.

It'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.

What'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.
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 22, 2023, 11:52:16 pm
Code: [Select]
    struct Info{
        char name[30];
        int age;
        struct address{
            char area_name[39];
            int house_no;
            char district[39];
        };
    };

I can refer to "house_no" so long as I qualify the reference to it with Info.Address. But how can one do that in Ada, nest structure declarations in that way? That's the question I'm struggling to find an answer too...

Oberon is similar to Ada for these types of declarations. In Oberon this is written as:

Code: [Select]
TYPE
  Info = RECORD
    name: ARRAY 30 OF CHAR;
    age: INTEGER;
    address:
      RECORD
        areaName: 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: [Select]
TYPE
  Name = ARRAY 30 OF CHAR;
  Location = ARRAY 39 OF CHAR;

  Address = RECORD
    houseNo: INTEGER;
    areaName, district: Location;
  END;
   
  Person = RECORD
    name: Name;
    age: INTEGER;
    address: Address;
  END;
In Oberon entire records can be assigned so, given these declarations you could write:

Code: [Select]
VAR
  twin1, twin2: Person;
 
...
...
  twin2 := twin1;
  twin1.name := "John Smith";
  twin2.name := "Jane Smith";
...
...

Thank you this is most interesting.

Here is the current syntax for "defining a new type" (or rather "alias" might be the better term).

Code: [Select]
      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 "name as othername" is the way we declare "name" as being of user defined type "othername".

Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 23, 2023, 12:02:55 am
They are in fact in C11, "6.7.2.1 Structure and union specifiers", §13:
Quote
An unnamed member whose type specifier is a structure specifier with no tag is called an
anonymous structure; an unnamed member whose type specifier is a union specifier with
no tag is called an anonymous union. The members of an anonymous structure or union
are considered to be members of the containing structure or union. This applies
recursively if the containing structure or union is also anonymous.

They 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.

This is valid C:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

See this slightly later post for proof of that.

https://www.eevblog.com/forum/programming/c-and-its-many-oddities/msg4654957/#msg4654957 (https://www.eevblog.com/forum/programming/c-and-its-many-oddities/msg4654957/#msg4654957)
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 23, 2023, 12:06:30 am
Here we see a thing called 'address' and another thing called 'Address', it's a very odd syntax indeed.

It'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.

Oh I understand it, it's just a very contrived syntax, what I mean it could have been simpler.

Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 23, 2023, 12:10:29 am
Here we see a thing called 'address' and another thing called 'Address', it's a very odd syntax indeed.

It'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.

Yes. 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.

Not at all, where did I say I "don't want to allow declarations of hierarchical types directly"? which post are you interpreting that 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 inherently be an array. The reasons are expounded upon above.
Title: Re: C and its many quirks
Post by: TheCalligrapher on January 23, 2023, 01:02:26 am
They 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.

This is valid C:

Code: [Select]
typedef struct {
    int age;
    int height;
} Person[3];

See this slightly later post for proof of that.

Yes, 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: [Select]
    struct Info{
        char name[30];
        int age;
        struct address{
            char area_name[39];
            int house_no;
            char district[39];
        };
    };

This is not valid C.
Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 23, 2023, 04:42:22 pm
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: [Select]
      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: [Select]
dcl my_data as flag_table;

The above could also be:

Code: [Select]
      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.




Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 23, 2023, 05:03:39 pm
Code: [Select]
    struct Info{
        char name[30];
        int age;
        struct address{
            char area_name[39];
            int house_no;
            char district[39];
        };
    };

I can refer to "house_no" so long as I qualify the reference to it with Info.Address. But how can one do that in Ada, nest structure declarations in that way? That's the question I'm struggling to find an answer too...

Oberon is similar to Ada for these types of declarations. In Oberon this is written as:

Code: [Select]
TYPE
  Info = RECORD
    name: ARRAY 30 OF CHAR;
    age: INTEGER;
    address:
      RECORD
        areaName: 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: [Select]
TYPE
  Name = ARRAY 30 OF CHAR;
  Location = ARRAY 39 OF CHAR;

  Address = RECORD
    houseNo: INTEGER;
    areaName, district: Location;
  END;
   
  Person = RECORD
    name: Name;
    age: INTEGER;
    address: Address;
  END;
In Oberon entire records can be assigned so, given these declarations you could write:

Code: [Select]
VAR
  twin1, twin2: Person;
 
...
...
  twin2 := twin1;
  twin1.name := "John Smith";
  twin2.name := "Jane Smith";
...
...

In your second example of a 'TYPE' it seems that that type 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: [Select]
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: [Select]
record.address = master_record.address;
record.phone_numbers = master_record.phone_numbers;

So I was never a fan of 'by name'.

Title: Re: C and its many quirks
Post by: Sherlock Holmes on January 23, 2023, 05:18:01 pm
Actually just perusing the ANSI X3.74-1987 standard, there is no 'by name' option, it was basically part of old "full PL/I".
Title: Re: C and its many quirks
Post by: cfbsoftware on January 24, 2023, 10:17:17 pm
In your second example of a 'TYPE' it seems that that type has no name, whereas the first one has a name of 'Info', so these are alternative ways of declaring a structure instance?
The type in my second example does have a name. I renamed it to Person from Info - just a personal preference ;)