[META] Talking about talking about C.

S

Seebs

So, watching the typedef battles, something has become clear to me.

Engineers suck at communicating.

Underneath it all, it is perhaps useful to remember that most of the
active participants here are people who have successfully written reasonably
large programs in C, so however they're thinking about C inside their heads,
it *works*. Maybe it's not exactly correct, but at the bare minimum, you
can be reasonably confident that it's a good enough model to have both
explanatory and predictive power for the behavior of programs on real
machines.

One of the most useful non-engineering skills I've ever applied to engineering
is learning to communicate better. Interestingly, writing clearly, while
certainly useful, is by far the lesser part of this. The big thing is to
learn to listen better. And I still have a long way to go on that.

A friend of mine gave me an excellent summary of a useful tactic when someone
who is otherwise apparently pretty rational or well-informed says something
obviously false:
Rather than thinking of it as false, think of it as true, and try
to figure out what it could be true *of*.

That's certainly contrary to the way engineers usually think! However, it's
very useful.

Here's an example of how I might apply that. It is obvious to me that size_t
is distinct from any of the standard unsigned integer types. Someone comes
along and tells me that size_t is the same as one of those types. Obviously
this is untrue... But wait! He's no idiot. What's he talking about?

Well, it turns out, what he's saying is quite true if, instead of talking
about the abstract language spec, I talk about any real implementation I've
ever heard of. On any real implementation I've seen, size_t is the same
type as one of unsigned short, unsigned int, unsigned long, or unsigned long
long. I've never heard of an exception. So actually, he's saying something
true, but he's talking about something other than what I'm talking about. If
I understand this, I can get somewhere. If I don't, I'm going to spend a
lot of time telling him that he's wrong, which he's not going to believe,
because he's tested his claim and it's obviously true.

Once we've got that figured out, we can potentially have a productive
discussion about whether it's more useful or effective to think about types
in terms of logical types or in terms of the compatibility rules that
are invoked when you try to assign a 'foo *' to a 'bar *'. Both ways of
thinking about types work. You can write large programs thinking about
it either way. Furthermore, each way of thinking about types will expose
you to some problems -- which the other avoids.

The same thing comes up when, say, someone talks about "the stack". All
the experienced C programmers know that C doesn't have a stack, except the
ones who know that C does have a stack. There are at least three reasonably
plausible ways of thinking about this. You can treat it as a contiguous
block of memory which always grows in the same direction. Sure, it's not
exactly right, but it'll work well enough most of the time, and it's simple.
You can treat it as totally separate activation records. You can think of
it more like a LIFO queue, without any regard to how it goes together.

All of these models *work*. None of them are exactly mandated. If, instead
of calling people "wrong" when they use a different model, you try to
understand the model they're using and see how it could be useful to you,
you're more likely to learn something.

Learning to distinguish between the thing you're modeling, and your model
of it, is really useful. It can make you a better programmer. It can
also reduce, dramatically, the number of clueless jerks you encounter on
Usenet.

-s
 
M

MartinBroadhurst

So, watching the typedef battles, something has become clear to me.

Engineers suck at communicating.

No, everyone sucks at communicating.
A friend of mine gave me an excellent summary of a useful tactic when someone
who is otherwise apparently pretty rational or well-informed says something
obviously false:
        Rather than thinking of it as false, think of it as true, and try
        to figure out what it could be true *of*.

Much too absolute. If someone says that all crows are white, it is
false. It's the height of impertinence to nod patronisingly while
deciding inwardly that they're actually talking about polar bears.
Here's an example of how I might apply that.  It is obvious to me that size_t
is distinct from any of the standard unsigned integer types.

No, no! It's distinct from *all but one* of the standard unsigned
integer types.
All of these models *work*.  None of them are exactly mandated.  If, instead
of calling people "wrong" when they use a different model, you try to
understand the model they're using and see how it could be useful to you,
you're more likely to learn something.

People will no more agree that they are arguing about different
"models" than they will agree that they are arguing about different
"subjectivities".

Martin
 
K

Keith Thompson

Seebs said:
So, watching the typedef battles, something has become clear to me.

Engineers suck at communicating.

Underneath it all, it is perhaps useful to remember that most of the
active participants here are people who have successfully written reasonably
large programs in C, so however they're thinking about C inside their heads,
it *works*. Maybe it's not exactly correct, but at the bare minimum, you
can be reasonably confident that it's a good enough model to have both
explanatory and predictive power for the behavior of programs on real
machines.

One of the most useful non-engineering skills I've ever applied to engineering
is learning to communicate better. Interestingly, writing clearly, while
certainly useful, is by far the lesser part of this. The big thing is to
learn to listen better. And I still have a long way to go on that.

A friend of mine gave me an excellent summary of a useful tactic when someone
who is otherwise apparently pretty rational or well-informed says something
obviously false:
Rather than thinking of it as false, think of it as true, and try
to figure out what it could be true *of*.

That's certainly contrary to the way engineers usually think! However, it's
very useful.

Well said. I probably haven't worked hard enough at this myself in the
typedef thread.

Of course I can't resist the urge to quibble with some of the details
even in this post. :cool:}
Here's an example of how I might apply that. It is obvious to me that size_t
is distinct from any of the standard unsigned integer types. Someone comes
along and tells me that size_t is the same as one of those types. Obviously
this is untrue... But wait! He's no idiot. What's he talking about?

Well, it turns out, what he's saying is quite true if, instead of talking
about the abstract language spec, I talk about any real implementation I've
ever heard of. On any real implementation I've seen, size_t is the same
type as one of unsigned short, unsigned int, unsigned long, or unsigned long
long. I've never heard of an exception. So actually, he's saying something
true, but he's talking about something other than what I'm talking about. If
I understand this, I can get somewhere. If I don't, I'm going to spend a
lot of time telling him that he's wrong, which he's not going to believe,
because he's tested his claim and it's obviously true.

You raise a point that I had mostly ignored: size_t could be a typedef
for something other than one of the five predefined unsigned integer
types (you forgot unsigned char). In particular, it could be a typedef
for one of the extended unsigned integer types. (C99 only; C90 didn't
have extended integer types.)

(Note that the description of the 'z' modifier for fprintf implicitly
assumes that a size_t argument is not promoted, and therefore that
size_t is not unsigned short or unsigned char. Note also that a
strict reading implies that size_t cannot be a typedef for plain
char, even if char happens to be unsigned, because char is not
one of the "unsigned integer types", even if it's an integer type
that's unsigned. I'd be astonished if either of these mattered
for any real-world implementation.)

So saying that size_t is the same as one of the standard unsigned
integer types is imprecise. But saying that size_t is the same as one
of the "unsigned integer types" (as that term is defined in C99
6.2.5p6) is both precise and correct.

C99 6.7.7p3:
A typedef declaration does not introduce a new type, only a synonym
for the type so specified.
That's about as clear as it can be.

The title of 6.7.7 is "Type definitions". The introductory subsections
for several standard headers refer to types (such as size_t) being
"defined". The only consistent conclusion is that "defining" a type
does not "introduce" (or create) a new type.

Thus my position, that size_t is not a distinct type, but is the same
type as one of the unsigned integer types. And this is on the level of
the abstract language spec, *not* with respect to any particular
implementation. The choice of which unsigned integer type size_t is the
same type as is implementation-specific. The fact that it's the same as
one of them is not.
Once we've got that figured out, we can potentially have a productive
discussion about whether it's more useful or effective to think about types
in terms of logical types or in terms of the compatibility rules that
are invoked when you try to assign a 'foo *' to a 'bar *'. Both ways of
thinking about types work. You can write large programs thinking about
it either way. Furthermore, each way of thinking about types will expose
you to some problems -- which the other avoids.

I understand that you think of size_t as a distinct type. I agree 100%
that it's useful to think of size_t as a distinct *something*. The
point where I disagree is the use of the word "type" to describe it.

Yes, if I program *as if* size_t were an additional predefined
integer type, distinct from all others, that's likely to lead me
to write good and/or portable code. (Similarly, I tend to pretend
that compound statements require braces, even though of course
they don't.) And the "size_t is a distinct type" model is simpler
than the "size_t is the same as one of the unsigned integer types,
but which one it is depends on the implementation, and writing code
as if it were a distinct type is likely to lead to better results"
model. It's just that the latter model is correct -- assuming
that I use the word "type" the same way the standard does.
The same thing comes up when, say, someone talks about "the stack". All
the experienced C programmers know that C doesn't have a stack, except the
ones who know that C does have a stack. There are at least three reasonably
plausible ways of thinking about this. You can treat it as a contiguous
block of memory which always grows in the same direction. Sure, it's not
exactly right, but it'll work well enough most of the time, and it's simple.
You can treat it as totally separate activation records. You can think of
it more like a LIFO queue, without any regard to how it goes together.

All of these models *work*. None of them are exactly mandated. If, instead
of calling people "wrong" when they use a different model, you try to
understand the model they're using and see how it could be useful to you,
you're more likely to learn something.

On the other hand, assuming the contiguous block of memory model can
lead to errors. For example, you might assume that comparisons of
addresses between different function calls (perhaps logged with
fprintf(log_file, "%p", ...)) tells you something about the calling
sequence. (And on most implementations, it does.)

On the other other hand, it's certainly possible to have a mental
model of "the stack" as a contiguous block of memory that always
grows in a consistent direction and still write good and portable
code. But it requires avoiding depending on some of the implications
of that model. Personally, I prefer to use a mental model that,
though it might be more complex and/or abstract, doesn't make me
keep track of which implications I can actually depend on and which
I can't. In addition, the rule that you can't compare pointers to
 
S

Seebs

Of course I can't resist the urge to quibble with some of the details
even in this post. :cool:}

Of course! :)
You raise a point that I had mostly ignored: size_t could be a typedef
for something other than one of the five predefined unsigned integer
types (you forgot unsigned char). In particular, it could be a typedef
for one of the extended unsigned integer types. (C99 only; C90 didn't
have extended integer types.)
Right.

So saying that size_t is the same as one of the standard unsigned
integer types is imprecise. But saying that size_t is the same as one
of the "unsigned integer types" (as that term is defined in C99
6.2.5p6) is both precise and correct.

Yes.

However, I'm not sure it's *useful* -- so far as I can tell, any program
which is correct only if that is true is logically incorrect.
C99 6.7.7p3:
A typedef declaration does not introduce a new type, only a synonym
for the type so specified.
That's about as clear as it can be.

Yes. I think the problem is that the word "type" is used in two different
ways in the standard; sometimes to refer to the underlying thing that has
to be compatible, sometimes to the relation between a name and that thing.
The title of 6.7.7 is "Type definitions". The introductory subsections
for several standard headers refer to types (such as size_t) being
"defined". The only consistent conclusion is that "defining" a type
does not "introduce" (or create) a new type.

I'm inclined to agree.
Thus my position, that size_t is not a distinct type, but is the same
type as one of the unsigned integer types. And this is on the level of
the abstract language spec, *not* with respect to any particular
implementation. The choice of which unsigned integer type size_t is the
same type as is implementation-specific. The fact that it's the same as
one of them is not.

Yup. But there's no specific type it's necessarily the same as, and it's
possible (though unheard of) for an implementation to have no other visible
type which is the same as it.

Huh. Actually, that leads to an interesting question.

We already know that "long" and "int" can be distinct types even when they
have the same representation.

Imagine, if you will, an implementation which creates a new type:
__SIZE_T
which is a 32-bit unsigned integer type which is distinct from unsigned long,
but which is an extended unsigned integer type.

So far as I can tell, it's fine for size_t to then be a typedef for __SIZE_T,
which is incompatible with EVERY other type.
I understand that you think of size_t as a distinct type. I agree 100%
that it's useful to think of size_t as a distinct *something*. The
point where I disagree is the use of the word "type" to describe it.

I think it'd be a lot easier to work on that if the language had better
language for the distinction between the things which are defined by
Yes, if I program *as if* size_t were an additional predefined
integer type, distinct from all others, that's likely to lead me
to write good and/or portable code. (Similarly, I tend to pretend
that compound statements require braces, even though of course
they don't.) And the "size_t is a distinct type" model is simpler
than the "size_t is the same as one of the unsigned integer types,
but which one it is depends on the implementation, and writing code
as if it were a distinct type is likely to lead to better results"
model. It's just that the latter model is correct -- assuming
that I use the word "type" the same way the standard does.

Well, the same way the standard does sometimes. I think mine is correct
if you use "type" the way it's used in the description of <stddef.h>.
And that's really the problem -- we seem to have two quite clearly
incompatible usages. I suppose in theory this is a defect. It's mostly
a harmless one, though -- this is the first time I've ever seen it come
up.

More interestingly, so far as I can tell, there's not a single case on the
table of either way of talking about types creating a problem for an actual
user thinking about or writing in C. They're incompatible with each others'
premises and terminology, but each seems to be internally consistent and
consistent with at least some of the usage in the standard.
(And as usual, that was a lot longer than I thought it would be.)

But informative.

-s
 
S

Seebs

No, no! It's distinct from *all but one* of the standard unsigned
integer types.

It could be distinct from all of them -- it could be an extended unsigned
integer type.

However, I think you're missing the point of what I'm saying. Consider
that I almost certainly understand how typedef works and so on -- I spend
a decade on the ISO C committee. You might, then, reasonably conclude
that, especially after spending a couple of days arguing about this very
point and citing the standard, I *probably* actually understand it.

So what on earth is happening when I make this statement which appears to
be false? Presumably, I must be trying to express something different.

And that is this: Even if we know, for sure, that some header somewhere
says:
typedef unsigned long size_t;
it is still possible, and useful, to distinguish between "size_t" and
"unsigned long". It is better to write:
printf("%zu\n", sizeof(x));
than
printf("%lu\n", sizeof(x));

Why? Because, even though it is true that size_t is almost certainly*
defined in terms of some other type, it is *logically* distinct, and treating
it as though it were completely distinct will almost inevitably produce
better code than treating it as though it were not completely distinct.

-s
[*] Actually, on thinking about it, I am not sure this is the case. So
far as I can tell, an implementation is permitted to have size_t itself
*be* the extended unsigned integer type, at which point, it's not an alias
for anything. I certainly can't conceive of a strictly conforming
program which could show such an implementation to be in error.
 
S

Seebs

You just made that up.
Nope!

The standard says that size_t is
"the unsigned integer type of the result of the sizeof operator".

Yes indeedy.

But "unsigned integer type" includes two subcategories:

* standard unsigned integer types (short, int, long, etc.)
* extended unsigned integer types (???)

See 6.2.5 (Types), paragraphs 4 and 6. The standard allows you to have
more integer types than are denoted by the usual range from unsigned char
to unsigned long long. While this doesn't come up very often, it might
make sense for an implementation to, say, use the common 8/16/32/64 types
for the standard unsigned integer types, then also provide at least one
extended unsigned integer type, such as a 24-bit or 48-bit type.

An implementor who hated you could in theory use 64 for all the standard
unsigned integer types except unsigned char, and then have the 16-bit
and 32-bit types be extended unsigned integer types.

Re-reading it, though, it seems that the extended types have to use
identifiers reserved for any use (footnote 28). So it seems to me that
there must exist some name for that type which is not size_t, so
size_t has to be an alias for some type, though there may be no way
for standard code to use that type directly.

-s
 
K

Keith Thompson

Seebs said:
[*] Actually, on thinking about it, I am not sure this is the case. So
far as I can tell, an implementation is permitted to have size_t itself
*be* the extended unsigned integer type, at which point, it's not an alias
for anything. I certainly can't conceive of a strictly conforming
program which could show such an implementation to be in error.

If size_t is a typedef for an extended unsigned integer type,
that type has a name which is an implementation-defined keyword
(or perhaps a sequence of keywords like "unsigned __int32").

If size_t itself were an extended unsigned integer type, then size_t
would be a keyword.

A strictly conforming program can use "size_t" as an identifier,
for example as the name of an automatic variable.
 
K

Keith Thompson

Seebs said:
Re-reading it, though, it seems that the extended types have to use
identifiers reserved for any use (footnote 28). So it seems to me that
there must exist some name for that type which is not size_t, so
size_t has to be an alias for some type, though there may be no way
for standard code to use that type directly.

A conforming program can use the type name directly. (A strictly
conforming, or even a portable or "clc-compliant" program, cannot.)
 
S

Seebs

Such a program can be non-portable, but it's not necessarily logically
incorrect.

Interesting point!
The initialization, which is non-portable, might be intended as a
compile-time assertion that size_t is a typedef for unsigned long.
Maybe I have a reason to want my program to compile only if that
assumption is correct. Maybe it reduces the amount of testing I
have to do. Or maybe I just want to see how it compiles as a way
of learning more about the implementation I'm using -- which is a
perfectly valid goal.

As a compile-time assertion, that's sort of clever.
Hmmm. I don't think I agree.
If a "type" is sometimes, as you say, "the relation between a name and
that thing", then in that sense the declarations in <stddef.h> *create*
types. But we know that typedefs *don't* create types, because 6.7.7p3
says they don't.

Ahh, but the key here is *sometimes*. My assertion is that 6.7.7 is using
the word "type" in the sense of "underlying thing", and that the <stddef.h>
section is using the word "type" in the sense of "relation between name and
thing".

Consider that, when you're looking at <stddef.h>, it's irrelevant to you
whether size_t is the same as any other type or not -- you are only concerned
with the fact that you can declare things of the type size_t after you
have included the header. But when you're reading 6.7.7, you're looking
into the actual underlying question of how typedef works. In that context,
you *do* need to know about that distinction -- that it is just creating
a new name for an existing thing.
I suspect (of course, correct me if I'm wrong) your reasoning was
something like this:
1. <stddef.h> defines types.
2. Defining types means creating types.

I'm not sure about this. The more I think about it, the more I think that
"creating" is the wrong interpretation of "defining", and that a whole lot
of the disputes seem to come from the assertion that to define something is
to create it.
If so, I think step 2 is where you went astray.

I think it is, at any event, a claim that I'm currently inclined to
reject.
I'm not sure it is possible. size_t must be an "unsigned integer
type" (7.17p2). The "unsigned integer types" are the five "standard
unsigned integer types" plus the "extended unsigned integer types"
(of which there are zero or more). 6.2.5 doesn't actually say that
each of the extended unsigned integer types has a name, but I think
it assumes that it does; a footnote on the sentence that introduces
extended integer types discusses the form of implementation-defined
keywords.

Yes.

Thus the qualifier "visible". If the implementation used __SIZE_T_MAGIC
as the type that size_t is an alias for, there's no way for you to "see"
that. You can't interact with it, you can't use the name, you can't
do anything with it. The only *visible* type is size_t.
Yes. It's also fine for size_t to be a typedef for unsigned long,
which is incompatible with every other type. I don't see that the
__SIZE_T case is significantly different.

The difference is that __SIZE_T is reserved for *all* uses. The
implementation is free to prohibit you from declaring anything using
that spelling, so far as I can tell.
I think it does; they're called typedefs and structs types,
respectively.

Yeah, "typedef names" is actually pretty useful.

C would benefit from a way to tag whether the intent is to make an
incompatible new type or just to have an easier way to spell a type
without any incompatibilities.

-s
 
S

Seebs

If size_t is a typedef for an extended unsigned integer type,
that type has a name which is an implementation-defined keyword
(or perhaps a sequence of keywords like "unsigned __int32").

If size_t itself were an extended unsigned integer type, then size_t
would be a keyword.

A strictly conforming program can use "size_t" as an identifier,
for example as the name of an automatic variable.

Your argument is persuasive, as is the observation that the extended
types are required to have names that are reserved for any use by
the implementation.

-s
 
S

Seebs

A conforming program can use the type name directly. (A strictly
conforming, or even a portable or "clc-compliant" program, cannot.)

I am toying with a notion: Imagine a compiler which has extended types
which you are NOT allowed to use -- any attempt to declare an object of
these types gets you compiler errors. And which then has typedef "bless"
them, so a typedef name pointing at them can be used.

So far as I can tell, "reserved for any use" would permit this kind of
silliness.

-s
 
K

Keith Thompson

Seebs said:
Ahh, but the key here is *sometimes*. My assertion is that 6.7.7 is using
the word "type" in the sense of "underlying thing", and that the <stddef.h>
section is using the word "type" in the sense of "relation between name and
thing".

Consider that, when you're looking at <stddef.h>, it's irrelevant to you
whether size_t is the same as any other type or not -- you are only concerned
with the fact that you can declare things of the type size_t after you
have included the header.

Perhaps, depending on just why I'm looking at it.
But when you're reading 6.7.7, you're looking
into the actual underlying question of how typedef works. In that context,
you *do* need to know about that distinction -- that it is just creating
a new name for an existing thing.



I'm not sure about this. The more I think about it, the more I think that
"creating" is the wrong interpretation of "defining", and that a whole lot
of the disputes seem to come from the assertion that to define something is
to create it.


I think it is, at any event, a claim that I'm currently inclined to
reject.

Cool.

Consider also something I mentioned in another thread. Look at the
definition of "definition" in 6.7p5. It's restricted to object
definitions, function definitions, enumeration constant (*not*
enumeration types), and typedef names. Other constructs that
create new types, such as struct declarations are not "definitions".
So defining something doesn't mean creating something. (Later I'll
try to figure out just what the standard really means by "defining"
something).

[...]
The difference is that __SIZE_T is reserved for *all* uses. The
implementation is free to prohibit you from declaring anything using
that spelling, so far as I can tell.

Hmm.

In this hypothetical implementation, the implementation chose
to reserve the name __SIZE_T as a keyword that's the name
for an extended integer type. Once it's done that, I'd expect
(non-portable) programs to be able to use that keyword to refer to
that same type.

I suppose the implementation could arbitrarily restrict the use
of that keyword other than in standard headers; I'm not quite sure
whether it would be legal for it to do so.

And I think we're off on a tangent.
Yeah, "typedef names" is actually pretty useful.

C would benefit from a way to tag whether the intent is to make an
incompatible new type or just to have an easier way to spell a type
without any incompatibilities.

Yeah, I think I may have mentioned that a few dozen followups ago. :cool:}
 
S

Seebs

Perhaps, depending on just why I'm looking at it.

I can't immediately think of a purpose for which I'd want to use the
information that size_t is probably an alias for a standard integer
type, except maybe for debugging a program which might be making
a mistake in relying on that in some way.
Consider also something I mentioned in another thread. Look at the
definition of "definition" in 6.7p5. It's restricted to object
definitions, function definitions, enumeration constant (*not*
enumeration types), and typedef names. Other constructs that
create new types, such as struct declarations are not "definitions".
So defining something doesn't mean creating something. (Later I'll
try to figure out just what the standard really means by "defining"
something).

My guess:

For things you generate code for, it's the thing that causes the
code to be generated.

For things that are names or words, it's the thing that gives
meaning to the name or word.
In this hypothetical implementation, the implementation chose
to reserve the name __SIZE_T as a keyword that's the name
for an extended integer type. Once it's done that, I'd expect
(non-portable) programs to be able to use that keyword to refer to
that same type.
I suppose the implementation could arbitrarily restrict the use
of that keyword other than in standard headers; I'm not quite sure
whether it would be legal for it to do so.

I'm pretty sure it would. It's reserved!

-s
 
J

Jorgen Grahn

....
On the other hand, assuming the contiguous block of memory model can
lead to errors. For example, you might assume that comparisons of
addresses between different function calls (perhaps logged with
fprintf(log_file, "%p", ...)) tells you something about the calling
sequence. (And on most implementations, it does.)

On the other other hand, it's certainly possible to have a mental
model of "the stack" as a contiguous block of memory that always
grows in a consistent direction and still write good and portable
code. But it requires avoiding depending on some of the implications
of that model. Personally, I prefer to use a mental model that,
though it might be more complex and/or abstract, doesn't make me
keep track of which implications I can actually depend on and which
I can't.

My mental model is approximately the Motorola 68000, with an actual
stack pointer register and everything. But I have never had problems
grasping that it might look very different ... and invalid code
doesn't look more right to me just because it fits my MC68000 model;

unsigned f(unsigned char* p) { return *(unsigned*)p; }

just looks /wrong/ (to take an example unrelated to stacks).

I don't think it's just me and my superior mind ;-) -- I think the
perils of very concrete mental models are exaggerated.

/Jorgen
 
S

Seebs

I don't think it's just me and my superior mind ;-) -- I think the
perils of very concrete mental models are exaggerated.

It varies a lot from person to person. Some people are more likely to
get "trapped" in a bad mental model, just as some people have a harder
time dropping a bad hypothesis than others.

-s
 
K

Keith Thompson

superpollo said:
Keith Thompson ha scritto: [...]
what about this?

http://cprog.tomsweb.net/cintro.html#2.4

"The type char may be equivalent to either signed char or unsigned char
(that depends on your compiler), but it is always a separate type from
either of these."

so what does equivalent mean?

It means that they have the same size, representation, bounds, and so
forth.
 
M

Marcin Grzegorczyk

Keith Thompson wrote:
[...]
Yes, if I program *as if* size_t were an additional predefined
integer type, distinct from all others, that's likely to lead me
to write good and/or portable code. (Similarly, I tend to pretend
that compound statements require braces, even though of course
they don't.)

You've got me lost here. Braces are in the syntax of a compound
statement (6.8.2).
 
K

Keith Thompson

Marcin Grzegorczyk said:
Keith Thompson wrote:
[...]
Yes, if I program *as if* size_t were an additional predefined
integer type, distinct from all others, that's likely to lead me
to write good and/or portable code. (Similarly, I tend to pretend
that compound statements require braces, even though of course
they don't.)

You've got me lost here. Braces are in the syntax of a compound
statement (6.8.2).

Sorry, "compound statement" was the wrong phrase.

What I really meant was that I tend to pretend that selection and
iteration statements require braces. For example, I'll write
if (condition) {
statement;
}
rather than
if (condition)
statement;

To some extent it's a habit I picked up from Perl, which does
require braces in similar contexts, but it also (IMHO) makes
maintenance easier.

But I remain aware that the *language* doesn't require the braces.
 
S

Seebs

Keith Thompson wrote:
[...]
Yes, if I program *as if* size_t were an additional predefined
integer type, distinct from all others, that's likely to lead me
to write good and/or portable code. (Similarly, I tend to pretend
that compound statements require braces, even though of course
they don't.)
You've got me lost here. Braces are in the syntax of a compound
statement (6.8.2).

I think what Keith is referring to is "the body of a control statement".

e.g.:
if (foo) {
bar;
}

So really, "as if the body of a control statement had to be a compound
statement".

-s
 

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,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top