what is the output of this program?

M

Martin

Sure, but there's undefined behavior and then there's undefined
behavior.

That seems to dilute somewhat the exhortations I read about undefined
behaviour being intolerable in all its manifestations. Now it seems there
is a continuum of undefined behaviours ranging from the tolerable (and
dare I say "acceptable") to the unacceptable. If not a continuum, then at
least split between tolerable and unacceptable.

Keith, have I read too much into your comment?
 
M

Martin

You may have read too much into the party line of
clc polemic. Keith rightly draws a distinction
between code that exhibits undefined behaviour
because it uses a machine-specific tool/technique/function
that is necessary for the purposes of the program to be
fulfilled,

The key word there, I think, is "exhibits". I was taking 'undefined
behaviour' to mean the manisfestation of the result from "... erroneous
program construct or of erroneous data" (ISO/IEC 9899:1999 (E) 3.4.3).

But, the ellipsis hides the important phrase "use of a nonportable or ..."

So undefined behaviour can be caused by non-portable C. I also note that
the cited paragraph's note says that an undefined behaviour can include
"behaving during translation or program execution in a documented manner
characteristic of the environment". This changes the view of undefined
behaviour I've seen promulgated that regards it as a heinous crime against
C, and is to be extirpated at all costs.

and code that exhibits undefined behaviour
because the programmer doesn't know spit about C. (I trust
that you will read that sentence in the spirit in which
it was intended, rather than take it /too/ literally.)

All I can say is that I think I know a lot about C, but I learn something
more about it each day ...

Writing code of the first kind is very sensible, but is merely
off-topic in comp.lang.c (which doesn't address platform
specifics). Writing code of the second kind is simply wrong.

Telling the difference between the two is not something that many clcers
are particularly skilled at doing, but it is quite clear that Keith
understands the difference.

Now I know about the difference, I will look for it. Thanks for the
response.
 
N

noagbodjivictor

C:\tmp>splint foo.c
Splint 3.1.1 --- 12 Mar 2007

foo.c(2,6): Function main declared to return void, should return int
  The function main does not match the expected type. (Use -maintype to
inhibit
  warning)
foo.c: (in function main)
foo.c(5,30): Expression has undefined behavior (value of left operand C is
                modified by right operand C++): C == C++
  Code has unspecified behavior. Order of evaluation of function parameters
or
  subexpressions is not defined, so if a value is used and modified in
  different places not separated by a sequence point constraining evaluation
  order, then the result of the expression is unspecified. (Use -evalorder
to
  inhibit warning)

Finished checking --- 2 code warnings

The correct answer is:
This program might output something or it might not.  It could (according to
an expert analysis of the C language standard) cause a demon to come flying
out of your nose.

P.S.
You didn't want to work there anyway, unless it is only those performing
interviews who are incompetent nitwits.

I really like this reply. Sir, thanks.
 
T

teapot

Richard said:
Three Headed Monkey said:



The third warning, as originally reported, was a single apostrophe, and
that's fairly easy to ignore.


I note that the single apostrophe remains even here. I'm not sure what
"lc" means by this apostrophe, but it's a legal diagnostic message.
Perhaps it means "this code is so screwed I just give up on the whole
thing", which would at least make sense.

That got me to do some experiments.

The good thing is, lcc-win rejects all return types with the
exception of `int' and equivalents (e.g., `signed' or `signed int',
but not `unsigned' or `unsigned int' or 'long'), e.g. --

float main(int argc, char **argv) { return 3.1415927f; }

wine lc -A -ansic -pedantic -O -c foo.c
Warning foo.c: 1 '
Error foo.c: 1 compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
Error z:\home\tpot\src\CLC\foo.c 1 Compiler error (trap). Stopping compilation
1 error

Interestingly, the following programs are also rejected with
exactly the same diagnostics --

int main(const int argc, char **argv) { return 0; }

int main(int argc) { return 0; }

wine lc -A -ansic -pedantic -O -c foo.c
Warning foo.c: 1 '
Error foo.c: 1 compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
Error z:\home\tpot\src\CLC\foo.c 1 Compiler error (trap). Stopping compilation
1 error

More interestingly, the next program is accepted --

float int unsigned signed int main(int argc, char **argv) { return 0; }

wine lc -A -ansic -pedantic -O -c foo.c
Warning foo.c: 1 multiple use of 'int'
Warning foo.c: 1 multiple use of 'signed'
Warning foo.c: 1 multiple use of 'int'
Warning foo.c: 1 parameter 'pointer to pointer to char argv' is not referenced
Warning foo.c: 1 parameter 'int argc' is not referenced
0 errors, 4 warnings
wine lc foo.obj -o foo.exe

wine foo.exe
echo $?
0

[snip]
 
K

Keith Thompson

[...]
[...]
The good thing is, lcc-win rejects all return types with the
exception of `int' and equivalents (e.g., `signed' or `signed int',
but not `unsigned' or `unsigned int' or 'long'), e.g. --

float main(int argc, char **argv) { return 3.1415927f; }

wine lc -A -ansic -pedantic -O -c foo.c
Warning foo.c: 1 '
Error foo.c: 1 compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
Error z:\home\tpot\src\CLC\foo.c 1 Compiler error (trap). Stopping compilation
1 error

Any time a compiler dies with an internal error (in this case, an
assertion failure), that's a bug in the compiler, even if it only
chokes on invalid programs. It doesn't violate standard, but it's
still a bug, at least as I use the word "bug". In this case, the
compiler *should* issue an error message that refers to the problem in
the code.

This is a QoI (quality of implementation) issue, not a conformance
issue.

(Let me emphasize again that I'm not picking on lcc-win.)
Interestingly, the following programs are also rejected with
exactly the same diagnostics --

int main(const int argc, char **argv) { return 0; }

int main(int argc) { return 0; }

wine lc -A -ansic -pedantic -O -c foo.c
Warning foo.c: 1 '
Error foo.c: 1 compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
Error z:\home\tpot\src\CLC\foo.c 1 Compiler error (trap). Stopping compilation
1 error

Again, a bug.
More interestingly, the next program is accepted --

float int unsigned signed int main(int argc, char **argv) { return 0; }

wine lc -A -ansic -pedantic -O -c foo.c
Warning foo.c: 1 multiple use of 'int'
Warning foo.c: 1 multiple use of 'signed'
Warning foo.c: 1 multiple use of 'int'
Warning foo.c: 1 parameter 'pointer to pointer to char argv' is not referenced
Warning foo.c: 1 parameter 'int argc' is not referenced
0 errors, 4 warnings
wine lc foo.obj -o foo.exe

wine foo.exe
echo $?
0

That program violates at least one constraint. An implementation
isn't required to reject a program that violates a constraint; it's
only required to issue at least one diagnostic. The warnings qualify
as diagnostics. (I'm a little surprised that the compiler treats this
particular problem as a warning rather than an error, but the standard
makes no distinction between warnings and errors.)
 
K

Keith Thompson

Martin said:
That seems to dilute somewhat the exhortations I read about undefined
behaviour being intolerable in all its manifestations. Now it seems
there is a continuum of undefined behaviours ranging from the
tolerable (and dare I say "acceptable") to the unacceptable. If not a
continuum, then at least split between tolerable and unacceptable.

Keith, have I read too much into your comment?

On further thought, I think I've come up with a clearer way to express
this.

Here in comp.lang.c, the phrase "undefined behavior" usually refers to
behavior that is not defined by the C standard (because that's how the
C standard defines the term).

In real-world programming, this is often too narrow. The distinction
I'm making is among the following:

1. Behavior that's defined by the C standard.

2. Behavior that's not defined by the C standard, but that is defined
by something else (e.g., by POSIX, by a particular implementation,
by a third-party library).

3. Behavior that is not, or that should not be, defined by *anything*.

Implementation-defined behavior (i.e., behavior that the C standard
doesn't define, but that it requires each implementation to define) is
somewhere between 1 and 2. Unspecified behavior is probably somewhere
between 2 and 3 (but it's not *really* a linear scale).

Class 3 covers things like ``i = i++;'' and ``i == i++'', as well as
stepping outside the bounds of an array, accessing to an object
outside its lifetime, reading an uninitialized object, defererencing a
null pointer, and so forth.

Roughly speaking, things in class 1 are topical in this newsgroup,
things in class 2 may be perfectly appropriate programming practices
(for code that doesn't need to be portable) but are usually more
topical in some other newsgroup than in this one, and things in class
3 should be avoided altogether.
 
H

Herbert Rosenau

The empty parens are old style, vs. main(void).

True, but void main() is not legal because main requires a return type
of int even in K&R C. There is no C where void main() is legal.


--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2R Deutsch ist da!
 
J

Joachim Schmitz

Herbert said:
True, but void main() is not legal because main requires a return type
of int even in K&R C. There is no C where void main() is legal.
void main() is not illegal, it is allowed to an implementation to provides
it as an extension.

Elsethread someone menioned that win-lcc provides that extension in it's
commercial version :cool:

Bye, Jojo
 
K

Keith Thompson

Herbert Rosenau said:
True, but void main() is not legal because main requires a return type
of int even in K&R C. There is no C where void main() is legal.

Depends on what you mean by "legal". The standard specifically
permits implementations to permit alternate declarations of main,
including ones where it returns void. Even on implementations where
it's not specifically permitted, "void main()" merely invokes
undefined behavior, so a compiler is not required to reject or even
diagnose it.

Of course that's no excuse for using "void main()" in a program (or,
worse yet, in a book) -- unless it's for a freestanding implementation
that specifically documents that form.
 
D

Dan

What do you mean C is not equal to C++ ?

Thats the point of the question, you are meant to get C==C++ and from the
answer you realise you are stupid because the program doesn't work.
 
R

Richard Bos

void main() is not illegal, it is allowed to an implementation to provides
it as an extension.

True as far as it goes, but it leaves me wondering why nobody ever uses
this as an excuse to write

struct mainreturn { int status; int error; float runtime; } main(void)

Richard
 
R

Richard Bos

Three Headed Monkey said:
You are ignoring third warning. If I add prototype for main like below,
compiler only issues one warning

#include <stdio.h>
void main(int argc, char **argv)
{
int C = 0;
printf("C %s C++\n", C == C++ ? "==" : "!=");
}

$ make foo9.exe
lc -ansic -pedantic -A -shadows -unused -O -c foo9.c -o foo9.obj
Warning foo9.c: 3 '
Error foo9.c: 3 compiler error in d:\lcc\mc71\types.c--assertion failure at line 868
Error c:\tmp\clc\foo9.c 3 Compiler error (trap). Stopping compilation
1 error
make: *** [foo9.obj] Error 1

Perhaps there is bug.

There most certainly is a bug. Several, in fact.

First, there are the obvious bugs in your code. Three, in all.

But there is also a bug in _either_ your compiler _or_ the way you have
installed it. That error message is clearly faulty. Strictly speaking
it's within the limits of the Standard, but then, so would "?" be.
However, I cannot imagine that any compiler writer would consider the
above to be a reasonable reaction to either void main() _or_ C==C++; and
as a compiler user, I certainly do not consider it reasonable.

If this broken message is as it was intended, that's a bug in the design
of the compiler. If it is not as was intended, but occurs because
there's a bug in the compiler itself, that's, surprise, a bug in the
execution of the compiler. If it is not due to the way the compiler was
written, but because you have one version of the compiler itself with
another version of its headers; or one compiler with the libraries of
another (more likely under Unix, but possible); or something similar,
that's a bug in the installation of the compiler.
I can't tell which is the case, but I'd be surprised if it did not turn
out to be one of those three. In the first two cases, the compiler
writer is at fault, and should remedy this; in the last case, whoever
installed it (presumably yourself) is at fault, and a clean reinstall
should fix the problem.

Richard
 
M

Martin

The standard specifically permits implementations
to permit alternate declarations of main,
including ones where it returns void.

When 'The Standard' is referred to on clc, does that indicate the C99
Standard? I must admit, I haven't delved into it because I'm not likely to
use a conformant compiler, and in my job I use C89.

If 'The Standard' means C99, is the permission to allow alternate return
types for main new to that?
 
S

santosh

Martin said:
When 'The Standard' is referred to on clc, does that indicate the C99
Standard? I must admit, I haven't delved into it because I'm not
likely to use a conformant compiler, and in my job I use C89.

Strictly speaking yes. There is only one currently effective C standard
and that's the 1999 one (ISO 9899:1999). But in practise the language
as defined by the previous standard, ISO 9899:1990, also called C89 or
C90 or ANSI C (the first and last designations are not strictly
accurate), is used more often than that defined ISO 9899:1999, with
amendments from 1995 incorporated.

So I suppose the consensus is that when the term "the standard" used
without any other qualifiers it refers to the currently effective
standard document, while one would use appropriate qualifiers (for
example "the C89 standard" or "the C90 standard" etc.) to designate
earlier standards.

In fact a dialect of "pre-ANSI" C called "K&R C" is also, by consensus,
topical here, though I personally know only C as defined by the 1990
and 1999 standards.
If 'The Standard' means C99, is the permission to allow alternate
return types for main new to that?

AFAICS, yes.
 
K

Keith Thompson

Richard Heathfield said:
Martin said: [...]
If 'The Standard' means C99, is the permission to allow alternate return
types for main new to that?

Yes. What's more, the alternate types are implementation-defined. Just
because one implementation documents (and thus permits the use of) const
struct tm ***main(), that doesn't mean it won't crash your machine when
compiled under some other implementation.

The *explicit* permission to allow alternate return types for main is
new in C99. But IMHO, that clause is redundant. Both the C90 and C99
standards explicitly allow extensions. Even if that weren't the case,
the standard doesn't define the behavior of main returning a type
other than int -- which means that an implementation is free to do so.

But, at least for hosted implementations, there's very little reason
to support return types other than int, and less reason to use return
types other than int.
 
K

Keith Thompson

Keith Thompson said:
But, at least for hosted implementations, there's very little reason
to support return types other than int, and less reason to use return
types other than int.

On re-reading that, it's not as clear as I thought it would be.

What I meant was that there's very little reason for compilers to
support return types (for main, obviously) other than int, and even
less reason for programmers to use return types other than int.
 
L

lawrence.jones

Keith Thompson said:
The *explicit* permission to allow alternate return types for main is
new in C99. But IMHO, that clause is redundant.

It isn't quite redundant because making it implementation defined
requires the implementation to document it.

-- Larry Jones

Start tying the sheets together. We'll go out the window. -- Calvin
 

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,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top