Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is this correct or not?

18 views
Skip to first unread message

jacob navia

unread,
Oct 20, 2011, 2:43:19 PM10/20/11
to
Hi the experts!

lccwin rejects this construct:

#define assert(e) \
((void) ((e) ? 0 : __assert (#e, __FILE__, __LINE__)))
#define __assert(e, file, line) \
((void)printf ("%s:%u: failed assertion `%s'\n", file, line, e),
abort())

lccwin reports
deque.c: 118 operands of ?: have illegal types 'int' and 'void'

The problem is that the two sides of the ? expression do not have the
same type: the left hand side is zero, (int) and the right side is (void)

gcc accepts that without any problem or warning.

Who is right?

Platform:

Macintosh pro, OS X 10.6.8.
gcc version 4.2.1 (Apple Inc. build 5664)

Thanks for your attention.

jameskuyper

unread,
Oct 20, 2011, 3:37:41 PM10/20/11
to
jacob navia wrote:
> Hi the experts!
>
> lccwin rejects this construct:
>
> #define assert(e) \
> ((void) ((e) ? 0 : __assert (#e, __FILE__, __LINE__)))
> #define __assert(e, file, line) \
> ((void)printf ("%s:%u: failed assertion `%s'\n", file, line, e),
> abort())
>
> lccwin reports
> deque.c: 118 operands of ?: have illegal types 'int' and 'void'
>
> The problem is that the two sides of the ? expression do not have the
> same type: the left hand side is zero, (int) and the right side is (void)

You can avoid the problem by using either (but not both!) of the
following two changes:

#define assert(e) \
(((e) ? (void)0 : __assert (#e, __FILE__, __LINE__)))

or

#define __assert(e, file, line) \
(printf ("%s:%u: failed assertion `%s'\n", file, line, e),
abort())

I prefer the second approach, if feasible, but whether or not it's
feasible depends upon whether or not you ever intend to use __assert()
directly, and if so, whether it would be in a context where it would
be a problem for it to expand into an expression with the type 'int'.

Note: C99 requires that the message printed by a failed assertion
should include the name of the enclosing function. The standard points
out that this name is the same as the value of __func__, which is new
in C99. However, it would have been perfectly feasible for C90 to have
imposed the same requirement without mentioning __func__; I have no
idea whether or not it actually did so. Is this meant to conform to
C99, or c90 (or neither)?

> gcc accepts that without any problem or warning.

Like almost all real-world compilers, gcc doesn't fully conform to any
C standard in its default mode, which is fine, since it does not claim
to be conforming in that mode. Adding the -pedantic option is
sufficient to turn on this mandatory diagnostic.

> Who is right?

6.5.15p3 lists the constraints on the types of the second and third
operands of the conditional operator. The combination (int, void)
doesn't fit any of the options listed in that section, so a conforming
implementation of C is required to generate a diagnostic, and is
permitted to reject such code.

gcc with no special options compiles GNU C, where the rules are
different; I don't know much about GNU C, but I would presume that gcc
handles this case correctly for that language.

gcc requires a minimum of -pedantic, and either -ansi or -std=c90 to
conform to C90, or -std=C99 to conform to C99. I don't remember
whether any of the additional -W options I normally turn on are also
required for conformance. I'd strongly recommend at least -Wall, even
if not needed for conformance.

gcc -pedantic and lccwin32 both print out the required diagnostic, so
both are correct.

jacob navia

unread,
Oct 20, 2011, 4:14:43 PM10/20/11
to
Le 20/10/11 21:37, jameskuyper a écrit :
> gcc -pedantic and lccwin32 both print out the required diagnostic, so
> both are correct.

Thanks for your explanations, I was really starting to get mad at this
problem.

The code above is furnished with the standard headers of the macintosh
in /usr/include/assert.h. Since Apple uses gcc since the creation of
NexT by Steve Jobs in the eighties, all headers are something like this:

#ifndef __GNUC__

int printf(const char * __restrict, ...);

#define assert(e) \
((void) ((e) ? 0 : __assert (#e, __FILE__, __LINE__)))
#define __assert(e, file, line) \
((void)printf ("%s:%u: failed assertion `%s'\n", file, line, e),
abort())

#else /* __GNUC__ */
// code full of __builtin(foo) __attribute__(whatever), etc
#endif

Now, lccwin takes of course the ifndef __GNUC__ path that
hasn't been tested since probably 20 years :-)

Of course gcc -pedantic doesn't help at all since in the
__GNUC__ part there is a completely different construct!


David Spencer

unread,
Oct 20, 2011, 4:58:36 PM10/20/11
to
jacob navia <ja...@spamsink.net> writes:

>The code above is furnished with the standard headers of the macintosh
>in /usr/include/assert.h. Since Apple uses gcc since the creation of
>NexT by Steve Jobs in the eighties, all headers are something like this:

Not any more. Apple has moved to LLVM.

>Now, lccwin takes of course the ifndef __GNUC__ path that
>hasn't been tested since probably 20 years :-)

Maybe it will now get tested.

--
dhs spe...@panix.com

Keith Thompson

unread,
Oct 20, 2011, 6:31:04 PM10/20/11
to
Not necessarily; clang (the compiler for LLVM) defines __GNUC__, at
least by default.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
0 new messages