Am I being too C++ like?

K

Keith Thompson

Rui Maciel said:
Do you see the ability to abstract types as being a benefit which is minor
enough that is not worth doing?

No, I overlooked that; see my followup to Tim Rentsch.
 
S

Stephen Sprunk

Yes, if you want an opaque type, a typedef is perfectly appropriate; I
should have mentioned that. By "opaque" in this case, I mean that the
code that uses the type doesn't need to know or care that the type is a
struct.

I haven't seen a whole lot of code like that.

What about FILE? Is there any implementation where that "opaque" type
_isn't_ actually a struct?

S
 
M

Malcolm McLean

What about FILE?  Is there any implementation where that "opaque" type
_isn't_ actually a struct?
Originally integers were used as file ids. This is still the system
with Fortran. Hence stdin, stdout and stderr could be simple defines.
 
S

Shao Miller

What about FILE? Is there any implementation where that "opaque" type
_isn't_ actually a struct?

It can be an integer to index into a fixed-size array of structs, where
there is a maximum number of open files. I've seen this in the
boot-loader for a particular OS, I believe.
 
K

Keith Thompson

Malcolm McLean said:
Originally integers were used as file ids. This is still the system
with Fortran. Hence stdin, stdout and stderr could be simple defines.

POSIX still uses small int values as file descriptors. Typically the
stdio mechanism is built on top of that. For example, open() returns an
int file descriptor, whereas fopen() returns a FILE*.

The requirement in the standard is:

FILE ... is an object type capable of recording all the information
needed to control a stream, including its file position indicator, a
pointer to its associated buffer (if any), an *error indicator* that
records whether a read/write error has occurred, and an *end-of-file
indicator* that records whether the end of the file has been reached

Assuming that the object type doesn't have to *directly* record all
this information, then FILE could easily be a typedef for int, with
the value used to index an array containing the actual information
(or some other scheme).

Certainly an implementation *could* make FILE something other than
a struct. The question is whether any actually do so.
 
P

Phil Carmody

Late to the party. Usenet is an occasional treat currently.

Ben Bacarisse said:
I don't see how that is supposed to work:

#include <stdio.h>

typedef __uint128_t uint128_t;
#define UINT128_C(X) ((uint128_t) (X))

int main(void)
{
uint128_t j = UINT128_C(0x10000000000000000ULL);

Don't force it to be a ULL before casting it to the 128-bit type then?
puts(j ? "ok" : "fail");
return 0;
}

prints "fail" (with a compiler-time warning about the constant being too
large for its type).

The UINTx_C macros usually need compiler magic and the manual says:

"There is no support in GCC to express an integer constant of type
__int128 for targets having long long integer with less then 128 bit
width"

Yikes, they did indeed write "less then".

Phil
 
B

Ben Bacarisse

Phil Carmody said:
Late to the party. Usenet is an occasional treat currently.



Don't force it to be a ULL before casting it to the 128-bit type then?

I don't see how that helps. It certainly doesn't alter the behaviour of
the example program when compiler with gcc.

<snip>
 
P

Phil Carmody

Ben Bacarisse said:
I don't see how that helps. It certainly doesn't alter the behaviour of
the example program when compiler with gcc.

I'm glad you replied - I now see that my assumptions were not 100% correct,
thanks for the nudge. I see the opening for 0x10000000000000000ULL to be of
no type, as p6 contains a "may" - there's no obligation for use of an
extended integer type. Presumably bad things happen in that case, and gcc
would barf, but that's not what you're seeing. Curious...

I will note that I find 6.4.4.1 p2 and p5+p6 to be somewhat conflicting,
and consider p2 to be the paragraph at fault, as the suffix doesn't
necessarily specify the type, it merely restricts the type it may have.

Phil
--
I'd argue that there is much evidence for the existence of a God.
Pics or it didn't happen.
-- Tom (/. uid 822)
 
T

Tim Rentsch

Keith Thompson said:
True. But that creates an artificial distinction between
self-referential and non-self-referential structs. My point is
that if you have a tag, you don't need a typedef.

It's not a distinction, just an observation. I already understood
the point; I was just making a factual correction.

Yes, if you want an opaque type, a typedef is perfectly appropriate; I
should have mentioned that. By "opaque" in this case, I mean that the
code that uses the type doesn't need to know or care that the type is a
struct.

I haven't seen a whole lot of code like that. It's more common, at
least in code I've seen, to declare a typedef for a struct type and then
write code that freely refers to its members.

That's easy to believe, and I think part of the reason for that
happening is lots of people giving blanket advice like "don't use
typedefs for structs" rather than talking about opaque types and
why it's good to use them. Hearing so many comments about not
using typedefs, it's easy for people to come away with the wrong
lesson.

Bad editing on my part; delete "are different identifiers".


Too may programmers *don't* follow any particular convention.
I see plenty of code like:

typedef struct foo {
/* ... */
} bar;

where the names "foo" and "bar" don't have any particular relationship.

Strictly following some naming convention (like "typedef struct foo_s {
... } foo") is better, but that's still two different identifiers to
keep track of. Using the same identifier for both is even better.

Actually I don't agree with this last piece of advice, but it
should be mostly irrelevant because properly done a struct
that is typedef'ed has its tag appear in a very small number of
places, ideally just two or three.


Promoting opaque types, and information hiding, are two of the
most important.
I mentioned it later: it gives the type a name that's a single
identifier, and saves a little typing.

More importantly, it saves horizontal space, which can be
important in places like function prototypes.

To my way of thinking the main reason to use typedef names
is to encourage use of information hiding and viewing of
various entities as abstract data types.
[...]

I agree that that's the main *appropriate* reason to use typedefs for
structs. Unfortunately, it's not the main reason programmers actually
use them.

But that's a reason to talk about information hiding, ADT's, and
opaque types /more/, not to insist more strenuously that typedefs
shouldn't be used. If you show examples of where it's good to
typedef a struct, that will both strengthen an understanding of
information hiding and ADT's, etc, and also make comments about
when /not/ to use typedefs more effective. Always typedef'ing
is bad; never typedef'ing is bad. A good developer needs to
understand the problems of both extremes.
 
B

Ben Bacarisse

Tim Rentsch said:
Keith Thompson <[email protected]> writes:
[on typedef structs]
More importantly, it saves horizontal space, which can be
important in places like function prototypes.

Pet peeve: why can't C's usual declaration syntax be used in function
prototypes (and definitions)? I.e.:

int memcmp(const void *s1, *s2; size_t n);

It seems a shame to me. I wonder if it was every considered.

<snip>
 
K

Keith Thompson

Tim Rentsch said:
Keith Thompson said:
To my way of thinking the main reason to use typedef names
is to encourage use of information hiding and viewing of
various entities as abstract data types.
[...]

I agree that that's the main *appropriate* reason to use typedefs for
structs. Unfortunately, it's not the main reason programmers actually
use them.

But that's a reason to talk about information hiding, ADT's, and
opaque types /more/, not to insist more strenuously that typedefs
shouldn't be used. If you show examples of where it's good to
typedef a struct, that will both strengthen an understanding of
information hiding and ADT's, etc, and also make comments about
when /not/ to use typedefs more effective. Always typedef'ing
is bad; never typedef'ing is bad. A good developer needs to
understand the problems of both extremes.

Ok, let me refine my stated position.

For a struct type that's not opaque, i.e., where the code that
uses the type is expected to refer to its members by name, I see
very little reason to use a typedef. My personal preference in
such cases is to declare the type with a tag, like "struct foo",
and then consistently refer to the type as "struct foo". The only
benefit of a typedef is to provide a one-word name for a type that
already has a two-word name. A drawback is that, in practice,
programmers don't use consistent conventions for the tag name and
the typedef name (using the same identifier for both alleviates
that problem). Another drawback is that you still need a tag for
self-referential types, but not for non-self-referential types,
a distinction that isn't necessary if you just use the tag.

I don't *strongly* feel that typedefs for such structs are a bad idea.
Having a one-word name for a type is of *some* benefit. I don't mind
tha fact that C++ in effect does this for you.

For a type that's truly opaque, i.e., where the code that uses it never
refers to members by name, a typedef is appropriate. In such cases,
having to refer to the type as "struct foo" unnecessarily leaks
information: client code shouldn't have to care that the type is a
struct. You should be able to change the type from a struct to an
integer without breaking client code. The type FILE in <stdio.h>
is a good example of this.

But I find that the former case is much more common than the latter.
 
I

Ian Collins

Tim Rentsch said:
Keith Thompson<[email protected]> writes:
[on typedef structs]
More importantly, it saves horizontal space, which can be
important in places like function prototypes.

Pet peeve: why can't C's usual declaration syntax be used in function
prototypes (and definitions)? I.e.:

int memcmp(const void *s1, *s2; size_t n);

It seems a shame to me. I wonder if it was every considered.

It doesn't work very well if the parameters aren't named in a function
declaration. You can't have a nameless variable declaration, but you
can have a nameless parameter in a function declaration.
 
K

Kaz Kylheku

Tim Rentsch said:
Keith Thompson<[email protected]> writes:
[on typedef structs]
I mentioned it later: it gives the type a name that's a single
identifier, and saves a little typing.

More importantly, it saves horizontal space, which can be
important in places like function prototypes.

Pet peeve: why can't C's usual declaration syntax be used in function
prototypes (and definitions)? I.e.:

int memcmp(const void *s1, *s2; size_t n);

It seems a shame to me. I wonder if it was every considered.

It doesn't work very well if the parameters aren't named in a function
declaration. You can't have a nameless variable declaration, but you

Is there a syntactic issue with a nameless declaration with multiple
abstract declarators like void *, *, **; ? Off the top of my head,
I can't see it.

(Suppose there is an issue; that can simply be disallowed. You can't
use that to write nameless paramters, but if there is just one declarator,
then you can. No need to throw out the concept just because it can't
"do" nameless params.)

Those should be allowed in structures too. It could be useful for padding.
Such a member would be initialized when the struct is initialized.

union { int x; char [256]; }; /* unnamed padding */

There exists an extension for unnamed unions in some compilers.
That works out:

struct { union { int x; int y }; int z };

That union is an unnamed member like char [256];
 
B

Ben Bacarisse

Kaz Kylheku said:
[on typedef structs]

I mentioned it later: it gives the type a name that's a single
identifier, and saves a little typing.

More importantly, it saves horizontal space, which can be
important in places like function prototypes.

Pet peeve: why can't C's usual declaration syntax be used in function
prototypes (and definitions)? I.e.:

int memcmp(const void *s1, *s2; size_t n);

It seems a shame to me. I wonder if it was every considered.

It doesn't work very well if the parameters aren't named in a function
declaration. You can't have a nameless variable declaration, but you

Is there a syntactic issue with a nameless declaration with multiple
abstract declarators like void *, *, **; ? Off the top of my head,
I can't see it.

No, I can't see how there can be. Currently, a comma ends a full
parameter declaration (named or nameless) but restoring its role as a
terminator for just the declarator (as in normal, non-prototype,
declarations) seems harmless. It may even be possible to have this
syntax co-exit with the correct one, though that was not my original
point -- I can't see any hope of a change now.

<snip>
 
G

Guest

yes but its a long ugly name. The C++ people seem to agree, once you've defined a struct you don't have to scatter "struct" keywords about the place.

[...] the most
important use case for typedef'ing a struct is to make a
(mostly) opaque type,

"...an important reason for typedef'ing a struct is to make an opaque type"

That's easy to believe, and I think part of the reason for that
happening is lots of people giving blanket advice like "don't use
typedefs for structs" rather than talking about opaque types and
why it's good to use them. Hearing so many comments about not
using typedefs, it's easy for people to come away with the wrong
lesson.

but that's not the only reason that people typedef structs. I do it becasue I think the syntax is poor. I hide other hard-to-read declaration syntax behind typedefs for the same reason. I don't do it because I got confused about opaque types.

So I don't think they have "learned the wrong lesson"
Actually I don't agree with this last piece of advice, but it
should be mostly irrelevant because properly done a struct
that is typedef'ed has its tag appear in a very small number of
places, ideally just two or three.

what drawbacks?

but
Promoting opaque types, and information hiding, are two of the
most important.
I mentioned it later: it gives the type a name that's a single
identifier, and saves a little typing.
To my way of thinking the main reason to use typedef names
is to encourage use of information hiding and viewing of
various entities as abstract data types.
[...]

I agree that that's the main *appropriate* reason to use typedefs for
structs. Unfortunately, it's not the main reason programmers actually
use them.

But that's a reason to talk about information hiding, ADT's, and
opaque types /more/, not to insist more strenuously that typedefs
shouldn't be used. If you show examples of where it's good to
typedef a struct, that will both strengthen an understanding of
information hiding and ADT's, etc, and also make comments about
when /not/ to use typedefs more effective.

always supposing the heavy typedefers actually /are/ confused

Always typedef'ing
 
I

Ike Naar

yes but its a long ugly name.

If "struct" is long and ugly, how about "typedef"?
The C++ people seem to agree, once you've defined a struct you don't
have to scatter "struct" keywords about the place.

What's more, in C++ you don't have to scatter "typedef" keywords about
the place either ;-)
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson said:
To my way of thinking the main reason to use typedef names
is to encourage use of information hiding and viewing of
various entities as abstract data types.
[...]

I agree that that's the main *appropriate* reason to use typedefs for
structs. Unfortunately, it's not the main reason programmers actually
use them.

But that's a reason to talk about information hiding, ADT's, and
opaque types /more/, not to insist more strenuously that typedefs
shouldn't be used. [snip]

Ok, let me refine my stated position. [snip]

A step in the right direction, I appreciate that. Just
two comments:

one: for future reference, I think it would help to
show examples of the different kinds of use cases, not
just describe them;

two: opaque types, ADT's, information hiding and OOP are
all related concepts but aren't exactly the same. Some
times it's okay to lump them all together, other times
it's important to distinguish them and talk about them
separately. I don't mean to offer advice about which
is which, only that it's important to think about in
which cases they should be distinguished and which not.
 
T

Tim Rentsch

(e-mail address removed) writes:

[responding selectively, mostly without the usual 'snip' indicators]
but that's not the only reason that people typedef structs. I do it
becasue I think the syntax is poor. I hide other hard-to-read
declaration syntax behind typedefs for the same reason. I don't do it
because I got confused about opaque types.

So I don't think they have "learned the wrong lesson"

The lesson I was talking about is "don't use typedefs". I
think you and I are in agreement that this is not the
right lesson.
[confusion about naming between tags and typedef names]

To my way of thinking the main reason to use typedef names
is to encourage use of information hiding and viewing of
various entities as abstract data types.
[...]

I agree that that's the main *appropriate* reason to use typedefs for
structs. Unfortunately, it's not the main reason programmers actually
use them.

But that's a reason to talk about information hiding, ADT's, and
opaque types /more/, not to insist more strenuously that typedefs
shouldn't be used. If you show examples of where it's good to
typedef a struct, that will both strengthen an understanding of
information hiding and ADT's, etc, and also make comments about
when /not/ to use typedefs more effective.

always supposing the heavy typedefers actually /are/ confused

I think you and I are pretty close on this issue actually, but
let me restate my comment from another perspective. What are
some examples where using typedef's makes sense, and some other
examples where using typedef's does not make sense? I believe
giving both kinds of examples will produce a better result.
 
I

Ian Collins

To my way of thinking the main reason to use typedef names
is to encourage use of information hiding and viewing of
various entities as abstract data types. In most cases, as
far as client code codes, the less one knows about a data
type the better; similarly, the more a type is treated as
an abstract data type, the better. The main cost of using
raw struct types is not in the typing but in the thinking:
for most code, not only do I not want to know what sort of
thing is being handled, I want NOT to know, because knowing
clutters ones thinking. Using a typedef name doesn't
prevent me from knowing (since after all I can go look at
the typedef in whatever header file defines it), but it
makes it easy not to know if one is so inclined. (And
those not so inclined can always just go look...)

After reading all the arguments presented here, I think this paragraph
sums the whole case pretty concisely. If it is not obvious from the
context that something is a struct (or an enum), it probably doesn't
matter to the programmer, so "struct" is superfluous. If it does
matter, it should be obvious from the context that something is a
struct, so "struct" is superfluous.

In the case of a self referencing struct, the keyword is required, but
it is only used within the context of the structure definition. It is
also the only case where a struct esquires a tag which may cause
inconsistencies in user's code. Giving the tag an ugly name and/or
style guidelines are sufficient to mitigate this.

Probably the worst situation is where both forms are used in one piece
of code.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top