Common misconceptions about C (C95)

P

Phil Carmody

Eric Sosman said:
Kaz said:
Have you checked all of the normative references? Maybe ISO 2382-1 has
a definition for operator. I don't have this document.

Have *you* found even one normative use of "operator" to
describe C's `while' keyword? Just one teeny-tiny use? One?
The term ``local variable'' also cannot be found in the standard.
[...]

Isn't there a difference between using a term not found
in the Standard, and using a Standard term in a way different
from the Standard's usage? Shall we discuss the `return'
function and the `void' qualifier and the `switch' type?

Excellent reply, better than I could have crafted this late in
the evening (morning). However, I think there is room to discuss
the function of 'do' ;-)

Phil
 
P

Phil Carmody

Keith Thompson said:
No, Gnus got it right. With "format=flowed", flowed text is indicated
by trailing spaces; there were none in Joe's article (at least not by
the time it got to me). See RFC 3676.

(What I found odd was the combination of "charset=UTF-8" and "7bit".
Perhaps the newsreader would change it to "8bit" if the article
contained any non-7bit characters.)

Guilty as charged.

Phil
 
F

frank

I like 'switch' type. Toggle, Rotary and Dimmer come to mind.

A cruel reminder to get back to work. I'm installing fans to move air
that operate off a dimmer. Does anyone know how efficient the $10
variety of dimmer from home depot is now?

It used to be you could hold up your hand to the plate, and it would be
hot.
 
F

frank

Eric Sosman said:
Kaz said:
My argument boils down to this: The Standard does not use the
term "operator" to refer to `while', so we shouldn't use it that way
either.
Works for me.

Have you checked all of the normative references? Maybe ISO 2382-1 has
a definition for operator. I don't have this document.

Have *you* found even one normative use of "operator" to
describe C's `while' keyword? Just one teeny-tiny use? One?
The term ``local variable'' also cannot be found in the standard.
[...]

Isn't there a difference between using a term not found
in the Standard, and using a Standard term in a way different from the
Standard's usage? Shall we discuss the `return' function and the
`void' qualifier and the `switch' type?

Excellent reply, better than I could have crafted this late in the
evening (morning). However, I think there is room to discuss the
function of 'do' ;-)

Phil

I think that pound for pound do-while is the trickiest control in C.
 
P

Phil Carmody

I didn't think that it can't be zero, merely that it's not
specified that it actually is anything at all. An implement
is at liberty to make it 0, surely?
sizeof (void) is a constraint violation and so a diagnostic is
required.


gcc does not compile C by default. If you ask it to, does it not
issue a diagnostic as required?

Only if you stamp your feet:

phil@duospaz:tmp$ gcc -std=c99 -c crap.c

phil@duospaz:tmp$ gcc -std=c99 -pedantic -c crap.c
crap.c:2: warning: invalid application of 'sizeof' to a void type

Phil
 
D

David Thompson

If I understand correctly, 'extern "C"' is not for converting arbitrary
C code to C++, but merely to tell the C++ compiler that the contained
declarations are for C functions. Interfacing C++ to C functions is
quite a different matter from compiling executable C code as C++.
Actually two or three things.

extern "C" on a (free) function declaration says that the function can
be called (from C++ code seeing this declaration) as a C function; in
practice this means the argument passing (and value return) and name
mangling (or otherwise). The function can be implemented/compiled in
either C, or C++, see next; and different people think differently as
to whether that counts as one or two features.

extern "C" on a (free) function definition also says the function can
be called as C, from either C++ or C code. Its *body* can still use
C++ features like new/delete and references and polymorphism, but its
interface can only use types compatible with C. You can use exceptions
within the C++, but whether it's safe to let them 'leak' to/across C
parts may depend on the (C++ and C) implementations. This can be
useful for example to provide a C library with a callback it can use.

The body of an extern "C" definition can contain code limited to the
(quite large) subset of C that is also valid and equivalent C++, but
there's no benefit in doing so; that might as well just remain a C
function (that C++ can call if needed).

Similarly if a function is implemented in C++ and will be called only
from C++, there's no benefit (and often some inconvenience) in using
extern "C" to make it C-compatible. But it is allowed.
 
R

Richard Bos

Keith Thompson said:
Perhaps C's mistake is having only *one* operator whose symbol looks
like an identifer. If C used "$" rather than "sizeof", this wouldn't
be an issue; similarly, if C had *more* operator keywords, "sizeof"
wouldn't be exceptional.

I've worked in languages where some operator symbols are punctuation,
and some are keywords. Ada, for example, has "not", "and", "or",
"mod", "rem", "abs", and probably others.


I find "sizeof int" to be a syntax error.

I consider "sizeof(type-name)" to be a different kind of expression
than "sizeof expr". In the latter, "sizeof" is the operator and
"expr" is the operand. In the former, the whole thing can be thought
of a nullary operator, one with no operands (a type name can't really
be an operand); it could easily have used a different syntax, like
"sizeof<<type-name>>". The standard's grammar doesn't describe it
this way, though.

I don't find that POV very helpful, since the result of either sizeof is
the same: the size of either the object, or the type.

Perhaps the best description for obviousness, though admittedly not for
exactitude, is that sizeof is an operator that takes either an
expression (which may be a single identifier, and IME most often is a
single pointer name with a * in front), _or_ a single cast. And it looks
best with a space between sizeof and argument in both cases.

Richard
 
I

Ioannis Vranos

David said:
The body of an extern "C" definition can contain code limited to the
(quite large) subset of C that is also valid and equivalent C++, but
there's no benefit in doing so; that might as well just remain a C
function (that C++ can call if needed).


If you mean "The body of an extern "C" definition can ==> only <== contain
code limited to...", as far as I know this is wrong.

A global C function, declared with extern "C" in C++ code, can be
implemented with full C code (usually C95 is supported by most popular
implementations), and not only with the common subset of C and C++.






--
Ioannis Vranos

C95 / C++03 Software Developer

http://www.cpp-software.net
 
K

Keith Thompson

I don't find that POV very helpful, since the result of either sizeof is
the same: the size of either the object, or the type.

Perhaps the best description for obviousness, though admittedly not for
exactitude, is that sizeof is an operator that takes either an
expression (which may be a single identifier, and IME most often is a
single pointer name with a * in front), _or_ a single cast. And it looks
best with a space between sizeof and argument in both cases.

Ah, but it's not a cast, and IMHO thinking of it as one only leads
to confusion.

A cast expression consists of an expression preceded by a
parenthesized type name. In "sizeof (int)" "(int)" is not a cast
expression.

A cast operator is the parenthesized type name that's part of a
cast expression. In "sizeof (int)", "(int)" is not followed by an
expression, so "(int)" is not a cast operator.

A sizeof expression is merely one of several constructs that use
a parenthesized type name. A cast is another. The parenthesized
type name in a sizeof expression is no more a cast than the comma
in a function call is a comma operator, or than the "(int)" in
"void foo(int)" is a cast.
 
I

Ioannis Vranos

Keith said:
A sizeof expression is merely one of several constructs that use
a parenthesized type name. A cast is another. The parenthesized
type name in a sizeof expression is no more a cast than the comma
in a function call is a comma operator, or than the "(int)" in
"void foo(int)" is a cast.


You are right for everything, except the comma operator. Comma is an
operator, check page 53 in K&R2.



--
Ioannis Vranos

C95 / C++03 Software Developer

http://www.cpp-software.net
 
S

Seebs

You are right for everything, except the comma operator. Comma is an
operator, check page 53 in K&R2.

You missed the point, and he was right. He said "the comma in a function
call". The thing separating the arguments in a function call is not a comma
operator, even though it has the same character representing it. The
arguments to a function are specifically the type of expression which can't
include comma operators (unless they're in a parenthesized subexpression).

-s
 
O

Oliver Jackson

Perhaps the best description for obviousness, though admittedly not for
exactitude, is that sizeof is an operator that takes either an
expression (which may be a single identifier, and IME most often is a
single pointer name with a * in front), _or_ a single cast. And it looks
best with a space between sizeof and argument in both cases.

YEAH that really clarifies everything thanks richard
 
K

Keith Thompson

Oliver Jackson said:
YEAH that really clarifies everything thanks richard

It's more accurate to say that sizeof is an operator that takes
either an expression or a parenthesized type name. I think that's
the way the standard describes it. It's not necessarily the way I
would have described it, as I've discussed elsethread, but following
the terminology of the standard is probably a good idea even if it
isn't ideal.
 
K

Kaz Kylheku

Ah, but it's not a cast, and IMHO thinking of it as one only leads
to confusion.

A cast expression consists of an expression preceded by a
parenthesized type name. In "sizeof (int)" "(int)" is not a cast
expression.

A cast operator is the parenthesized type name that's part of a
cast expression. In "sizeof (int)", "(int)" is not followed by an
expression, so "(int)" is not a cast operator.

The concept of a cast operator can exist independently of the cast expression.

The view that sizeof is being applied to a detached operator doesn't conflict
with anything.

If someone finds it hefpful, great.
 
K

Keith Thompson

Kaz Kylheku said:
The concept of a cast operator can exist independently of the cast
expression.

It can, but it doesn't, at least not in the language as described by
the standard or by any C textbook I've seen.
The view that sizeof is being applied to a detached operator doesn't
conflict with anything.

It conflicts with the terminology of the standard, and it encourages
the idea that the word "cast" refers to any parenthesized type name.
Neither "sizeof (int)" nor "void foo(int)" contains a cast. A cast
specifies a conversion; "sizeof (int)" does not.
If someone finds it hefpful, great.

Ok, but IMHO it's *more* helpful to think of it as a parenthesized
type name. Personally, I find it extremely useful to think in
terms of underlying concepts, and to avoid conflating different
constructs because they happen to use similar syntax.
 
R

Richard Tobin

The concept of a cast operator can exist independently of the cast
expression.
[/QUOTE]
It can, but it doesn't, at least not in the language as described by
the standard or by any C textbook I've seen.
[...]

Ok, but IMHO it's *more* helpful to think of it as a parenthesized
type name. Personally, I find it extremely useful to think in
terms of underlying concepts, and to avoid conflating different
constructs because they happen to use similar syntax.

I agree that is quite wrong to call it a cast operator, but I do think
it would be useful to give a name to the sequence

( type-name )

which is used wherever (three places I think) a type name is needed in
an expression. "Type-expression", perhaps.

-- Richard
 
R

Richard Bos

Oliver Jackson said:
YEAH that really clarifies everything thanks richard

Do note, though, that I did say that this is _not_ exact. It's not what
officially happens according to the Standard - it just looks remarkably
like it. Take it as a good way to get the spelling right, not to
understand the fundamentals.

Richard
 
D

David Thompson

<snip> I admit I'm playing a little fast-and-loose with C's typing, but what
_exactly_ am I losing in terms of type safety, <snip>

enum {
H_CONTENT_LENGTH,
H_CONTENT_TYPE,
};

struct http_content_length { int type; /*... */ };
struct http_content_type { int type; /* ... */ };

void http_content_length_print(struct http_content_length *, FILE *);
void http_content_type_print(struct http_content_length *, FILE *);
I assume you meant the second routine's param type to be ...length .
void http_header_print(void *header, FILE *fp) {
static void (*const print[])() = {
[H_CONTENT_LENGTH] = &http_content_length,
[H_CONTENT_TYPE] = &http_content_type,
};
int type = *(int *)header;
/* ... check bounds */
print[type](header, FILE *fp);
}
As already said, the call is unsafe. There are (at least have been)
machines where void* and some_struct* (or even int*) are different,
and passing the latter as if it were the former will cause chaos.

However, the standard does require that pointers to different *struct*
types have the same representation and alignment (colloquially called
'smelling the same') even across t.u. boundaries where the full type
may not be known. While the footnote that they be interchangeable as
arguments isn't normative, in practice they are on anything but DS9k
with the Jumbo Enhanced Perversity Option. So if you use structs for
all the actual routines/parameters, and e.g. struct http_any_header *
or just struct unknown * for the call, you're safe enough.

That said, if I wanted something like this type-safe I would just use
C++. In C I would stick with void* rather than going to the extra work
and clutter of something that, as you said, isn't enforced.
 
D

David Thompson

If you mean "The body of an extern "C" definition can ==> only <== contain
code limited to...", as far as I know this is wrong.
I didn't mean that. In fact my prior paragraph, which you snipped,
says a C++extern"C" definition can use C++ features in its body but
its interface (i.e. arguments and return) must be C compatible.

This paragraph says that *IF* you use C++ to write an extern"C"
function whose body does *only* C, the result is no better than just
writing the C function in C. Technically this follows from the general
principles for extern"C" and is redundant, but I stated it separately
because there was discussion of this exact point earlier; I don't
recall if it was in this thread, or another similar one.
 

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
474,007
Messages
2,570,266
Members
46,865
Latest member
AveryHamme

Latest Threads

Top