Horrible Visual C Bug!

J

JeffK.

Oliver said:
I would rather fire somebody who always loses the focus instead of such
really nonimportant points. BTW, I always use int main() as you
can see in my programms. But for this example it is absolutely
irrelevant.

There are bugs in the compilers, and I've witnessed differences arising
from
the use of void main vs int main. I've seen code compile on one
compiler that
would not on another. A lot of the problems lie in how the compiler is
designed.
Not all problems arise from deviation from language specs. Memory
allocation
and error handling can be extremely different from one system to
another, such
that the problem of portability, as noted above, can arise.

For those who always blame the programmer, my advice is to start using
other products. Someday you'll need employment, and there's lots of
older code that needs upgrading or, you'll use it as is and need to
figure
out how to get it to work on a newer computer. When you work on such
projects,
you become aware of vendor product shortcomings.

The issue I see with your project is that a more helpful error warning
routine would be helpful, such that you would be put on notice that
what you are doing is treading on dangerous ground. If you did turn on
all warnings and were unaware of what was there, a vendor criticism is
in order.
If you did not turn on your warnings, then this is something to do that
is good practice.

The bottom line in programming though is to keep the code simple. The
surprise you note is not really that uncommon when you start
experimenting
and not something you want to have to deal with on a project that has a
deadline
to meet.

But keep experimenting, and seeing what's out there!

JeffK.
 
M

Mark McIntyre

Yep. The compiler must complain about the syntax and diagnosable
semantic errors

But its neither of these, I think..
unless the standard says no diagnostic is required.
The standard says main "SHALL" return int. This means the program
is not well-formed if it doesn't, and since there's no exemption clause,
it needs a diagnostic.

I'd certainly like it to emit one.
 
R

Robert Hyatt

Oliver Brausch wrote:
There are bugs in the compilers, and I've witnessed differences arising
from
the use of void main vs int main.

There should be _no_ difference in how a program runs, whether you use
"int main()" or "void main()". That only tells the compiler that the
program returns a value, that most operating systems use as the "return
or completion code". IE exit(0); returns a zero completion code. As
does "return 0" in the main program. int or void should have _no_ effect
on how the program executes, however, it just affects whether the system
can determine whether it executed normally or not.

I've seen code compile on one
compiler that
would not on another. A lot of the problems lie in how the compiler is
designed.
Not all problems arise from deviation from language specs. Memory
allocation
and error handling can be extremely different from one system to
another, such
that the problem of portability, as noted above, can arise.
For those who always blame the programmer, my advice is to start using
other products. Someday you'll need employment, and there's lots of
older code that needs upgrading or, you'll use it as is and need to
figure
out how to get it to work on a newer computer. When you work on such
projects,
you become aware of vendor product shortcomings.
The issue I see with your project is that a more helpful error warning
routine would be helpful, such that you would be put on notice that
what you are doing is treading on dangerous ground. If you did turn on
all warnings and were unaware of what was there, a vendor criticism is
in order.
If you did not turn on your warnings, then this is something to do that
is good practice.

I don't think any vendor criticism is in order. In C, you can do _many_
things that a compiler can't verify whether it is right or wrong. IE you
can pass an integer to a function that requires a float. If the compiler
doesn't see both the caller and the callee, or a prototype for the callee,
then it _must_ assume you know what you are doing. If it does see it,
but you re-cast the int to a float, it is not going to work, and the compiler
should not complain since the cast operator indicates you know what you are
doing.

If you fail to follow normal programming practices, and it blows up when you
run the thing, that's hardly something to whack the vendor about. After all
you _can_ put your foot under a running lawnmower, but should you do so, you
don't have much reason to complain about the result. This is the same kind
of thing. You _can_ do some things, but the question is _should_ you do
them and if you do, who is responsible?
 
B

Bruno Desthuilliers

Dave C. wrote:
(snip - about why int main() instead of void main())
For these reasons I use int main (or would if I still used C!).
However, it would be nice to hear a purely logical reason

On some platforms (at least on unices, but C and Unix are very close),
the value returned by main() has some meaning for the system, and is
actually widely used in scripts (shell or more advanced). In a shell
script, a call to a program may be like a function call, and branching
or whatever may be done depending on the return value of a program.

BTW, I once had to write a C program on Windows to test the return value
as another one that made heavy batch processing, before launching a
second heavy-batch-processing program that depended on the first having
done its job correctly.

Does it give you a logical reason ?

Bruno
 
S

Sin

On some platforms (at least on unices, but C and Unix are very close),
the value returned by main() has some meaning for the system, and is
actually widely used in scripts (shell or more advanced). In a shell
script, a call to a program may be like a function call, and branching
or whatever may be done depending on the return value of a program.

BTW, I once had to write a C program on Windows to test the return value
as another one that made heavy batch processing, before launching a
second heavy-batch-processing program that depended on the first having
done its job correctly.

Does it give you a logical reason ?


Stepping back in...

What if the application in question is a Windows GUI app which returns
control immediatly to the calling batch file...? GUI applications usually
signal error/succes by visual and interactive means... The return code of
such applications often is of absolutly no importance.

Of course the ansi standard says you should write int main... But some
compilers (hence programmers) do not abide to it... Does it make those
compilers and programmers bad?

NO, unless they do it without knowing the consequences.

Alex.
 
C

Chris Torek

There should be _no_ difference in how a program runs, whether you use
"int main()" or "void main()". That only tells the compiler that the
program returns a value, that most operating systems use as the "return
or completion code".

Indeed. But what if this changes the calling sequence or function's
linker-level name?

The problem, you see, is that someone else -- over whom you have no
control -- has already written "int main()", in the code that calls
builds argc and argv and calls main() initially.

On typical boxes today, that code looks in part like this:

extern int main(int, char **);
...
exit(main(argc, argv));

Of course, the ANSI C standard requires that this work even if the
programmer wrote:

int main(void) {

so a less-typical box might actually have TWO startup routines, the
other looking like this:

extern int main(void);
...
exit(main());

Now suppose the C compiler uses a C++-style "name mangling" scheme
in order to distinguish between main(void) and main(int, char **).
The former compiles to 0$main$ and the latter to 2$i$ppc$main$.
At link time, this less-typical box scans the object files to see
whether the "main" symbol is 0$main$ or 2$i$ppc$main$, so as to
choose the correct call into main().

If you write something other than one of these two forms, then, your
program might fail to link.

Suppose that, instead of (or in addition to) name-mangling, we have
a stack-oriented machine in which main()'s return value is popped
and pushed (or no-op'ed) from the value stack to be passed to
exit(). If the value stack is empty at the initial call to main(),
and you use "void main()" (and if the compiler is doing name-mangling
you somehow manage to make it link despite not finding the right
name), then the startup routine's call to exit() (or exit() itself)
attempts to pop a value off an empty stack. The result is a runtime
exception when main() returns.

The latter may sound farfetched, but something remarkably similar
does happen on real implementations today if you manage to write code
of the form:

struct S { char a[100]; };

struct S main(int argc, char **argv) {

Typically one writes this accidentally, by mistakenly leaving off
the ";" at the end of the first line, and using "default int"
declarations that turn out not to be default int after all:

struct S {
char a[100];
} /* NOTE MISSING SEMICOLON */

main(int argc, char **argv) {
... code here using argc and/or argv ...
}

In this case, a number of compilers assume you "really meant":

void main(struct S *__secret_arg1, int argc, char **argv) {
...
/* returning a value assigns to *__secret_arg1, then returns */
}

so that argc and argv wind up having "peculiar values". (In fact,
on these systems today, argv seems to be junk or to contain the
environment variable list, and argc is some huge number. Yes,
I have debugged just such a problem. :) )

The point of all this is simple enough: if you write "int main()",
a big guy with a large bat is metaphorically standing right behind
your compiler-vendor, ready to whack him in the head if he makes
your code fail because of this. But, if you write "void main()",
the guy with the bat will not do anything to your compiler-vendor,
because you failed to keep *your* part of the bargain.

The "bargain" in question is the C standard, which has lists of
programming constructs and behaviors and says (not quite literally)
"if you do only these things, your vendor must do only those things."
As long as the things you need done are things *every* ANSI-C vendor
*must* do, you have little to lose by sticking to the standard.
You may or may not think you have much to gain, but history suggests
that in fact you *do* have something to gain.

In other words, if you write "int main()", you are quite probably
helping yourself, and if you write "void main()", you are quite
probably hurting yourself.

Note that this is *not* true for *other* places you (as a programmer)
might completely ignore the ANSI C standard. For instance, given
that this thread is (for some mysterious reason) cross-posted to
rec.games.chess.computer, you might have a chess game in which you
want to draw graphics in a window. ANSI C does not give you a way
to do this -- so the cost/benefit equation now swings heavily the
other way: "Cost of not using standard C: unknown, probably not
zero but probably not huge. Benefit: can achieve goal." Compare
that to "void main": "Cost: unknown, probably not zero but probably
not huge. Benefit: none."
 
M

Mark McIntyre

There should be _no_ difference in how a program runs, whether you use
"int main()" or "void main()".

This might be true on the limited set of machines you've used. On some
of the ones I've used, void main() could crash the system.

The OS required a return code to be in a register, and so it took one
out. But your app didn't put if there, so it grabbed some garbage. The
OS then acted on that garbage, and you can imagine what happens if the
garbage happened to be the error code for "the computer room is on
fire, shut down the cluster at once" or "the CPU is overheating,
instigate emergency procedures". Or even if it was only "this program
caused a memory violation and crashed, so please remove all files it
created since they're garbage"
 
M

Mark McIntyre

What if the application in question is a Windows GUI app

These don't have a main(). Windows GUI apps are not ISO C, so the
discussion is moot.
which returns
control immediatly to the calling batch file...? GUI applications usually
signal error/succes by visual and interactive means...

What, they signal to a batch visually? Amazing !!
The return code of such applications often is of absolutly no importance.

Depends, doesn't it?
Of course the ansi standard says you should write int main... But some
compilers (hence programmers) do not abide to it... Does it make those
compilers and programmers bad?

If hte compiler documents the effect of the behaviour, then no
problem. If it does /not/ then the progammer who uses it is bad.
 
B

Ben Taylor

can you smoke beef?
how?

Charlie Gibbs said:
A little voice inside my head starts screaming "Side effects!"
whenever I see something like this. My solution is simple:
don't do it.


"You can smoke beef, and you can smoke hash, but you can't smoke
corned beef hash." -- National Lampoon

--
/~\ (e-mail address removed) (Charlie Gibbs)
\ / I'm really at ac.dekanfrus if you read it the right way.
X Top-posted messages will probably be ignored. See RFC1855.
/ \ HTML will DEFINITELY be ignored. Join the ASCII ribbon campaign!
 
R

Richard Heathfield

Ron said:
Yep. The compiler must complain about the syntax and diagnosable
semantic errors unless the standard says no diagnostic is required.

That's not what the Standard says, though.

"5.1.1.3 Diagnostics
1 A conforming implementation shall produce at least one diagnostic message
(identified in an implementation-defined manner) if a preprocessing
translation unit or translation unit contains a violation of any syntax
rule or constraint, even if the behavior is also explicitly specified as
undefined or implementation-defined. Diagnostic messages need not be
produced in other circumstances.8)"

Nothing in there about diagnosable semantic errors.
The standard says main "SHALL" return int. This means the program
is not well-formed if it doesn't, and since there's no exemption clause,
it needs a diagnostic.

No, it doesn't. It's wrong, but the compiler is under no obligation to
diagnose it.

(BTW the rules are different for C++, and that might be what's thrown you.)
 
R

Richard Heathfield

Christian said:
Richard Heathfield said:
I occasionally conduct recruitment interviews for C programmers. At such
interviews, I always ask the programmer what main() returns. If he gets
the answer wrong, which does sometimes happen, it is unlikely that he
will get the job.

On the other hand, imagine you are in a job interview and you are asked:
What will this statement do?

i = 3;
a [i++] = i;

I recommend that you answer: It could store the number 3 or the number 4
into a [3]. Anything beyond that and you might confuse the interviewer.

I recommend that you answer: the second statement violates a "shall" outside
a constraint clause (specifically 6.5(2)), so no diagnostic is required,
but the behaviour is undefined, and the outcome is therefore unpredictable.
If that confuses the interviewer, so be it.
(These two possibilities alone would be enough to make you avoid a
statement like this, obviously. But don't mention that your program
could crash or worse because of this).

That could work against you, if the interviewer knows the language. And if
he doesn't know the language, he shouldn't be interviewing you anyway.
 
R

Richard Heathfield

Mark said:
(and someone responded with a quote from the MSVC 6 helpfile,
mentioning void main() but I managed to lose the post)

I was about to say "interesting, so MS finally documented it" but then
I noticed that this section begins "A special function called main is
the entry point to all C++ programs".

They've "fixed" this in Version 7, but it matters not, since Version 7
doesn't claim to be C99-conforming anyway.
 
F

Falcon Kirtarania

The relevance is intact, because the MS Visual Studio C++ .NET compiler will
also compile C.
 
F

Falcon Kirtarania

Christian Bau said:
Richard Heathfield said:
I occasionally conduct recruitment interviews for C programmers. At such
interviews, I always ask the programmer what main() returns. If he gets the
answer wrong, which does sometimes happen, it is unlikely that he will get
the job.

On the other hand, imagine you are in a job interview and you are asked:
What will this statement do?

i = 3;
a [i++] = i;

I recommend that you answer: It could store the number 3 or the number 4
into a [3]. Anything beyond that and you might confuse the interviewer.

Theoretically, it would execute:

LINE 1 WATCH: i == 3 true
LINE 2: a[3]==3, and at the end i=4

because i++ is a postdecrement and taxes place at the end of the line,
doesn't it? Or is it the statement?
 
F

Falcon Kirtarania

It said anyway, that it was in fact good code to have void and it would
simply return 0 or comething like that. Which is another example of how
Bill Gates fucked up the computing industry yet again.

Mark McIntyre said:
(and someone responded with a quote from the MSVC 6 helpfile,
mentioning void main() but I managed to lose the post)

I was about to say "interesting, so MS finally documented it" but then
I noticed that this section begins "A special function called main is
the entry point to all C++ programs".


--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>


----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---
 
F

Falcon Kirtarania

Theoretically, any undefined behavior should return an error (as in, the
standard should change). This might help solve the troubles of awful
programming.
]
 
F

Falcon Kirtarania

Robert Hyatt said:
There should be _no_ difference in how a program runs, whether you use
"int main()" or "void main()". That only tells the compiler that the
program returns a value, that most operating systems use as the "return
or completion code". IE exit(0); returns a zero completion code. As
does "return 0" in the main program. int or void should have _no_ effect
on how the program executes, however, it just affects whether the system
can determine whether it executed normally or not.

That is why such code is substandard. Perhaps, what the standard is getting
at is it is far better to return an error code than exit "normally" (or
assume that) regardless of what happened.
I don't think any vendor criticism is in order. In C, you can do _many_
things that a compiler can't verify whether it is right or wrong. IE you
can pass an integer to a function that requires a float. If the compiler
doesn't see both the caller and the callee, or a prototype for the callee,
then it _must_ assume you know what you are doing. If it does see it,
but you re-cast the int to a float, it is not going to work, and the compiler
should not complain since the cast operator indicates you know what you are
doing.

Such casts should generate a level 4 (highest level) warning anyway, just to
mention it, unless in very special cases such as when the types are like
char to int, AND the (int)char is not being written to above 127.
If you fail to follow normal programming practices, and it blows up when you
run the thing, that's hardly something to whack the vendor about. After all
you _can_ put your foot under a running lawnmower, but should you do so, you
don't have much reason to complain about the result. This is the same kind
of thing. You _can_ do some things, but the question is _should_ you do
them and if you do, who is responsible?

Where the standard is not specified, a decent compiler will logically extend
the syntax and normal operation to include a special case.
 
F

Falcon Kirtarania

Really, all it comes down to is that unless you really don't give a shit
what is in EAX after your program executes, you damn well better return int.
Theoretically, within standard, it could simply not set EAX on returning
void as it does for everything else. Then you would end up with return
codes that are pseudorandom numbers.

Chris Torek said:
There should be _no_ difference in how a program runs, whether you use
"int main()" or "void main()". That only tells the compiler that the
program returns a value, that most operating systems use as the "return
or completion code".

Indeed. But what if this changes the calling sequence or function's
linker-level name?

The problem, you see, is that someone else -- over whom you have no
control -- has already written "int main()", in the code that calls
builds argc and argv and calls main() initially.

On typical boxes today, that code looks in part like this:

extern int main(int, char **);
...
exit(main(argc, argv));

Of course, the ANSI C standard requires that this work even if the
programmer wrote:

int main(void) {

so a less-typical box might actually have TWO startup routines, the
other looking like this:

extern int main(void);
...
exit(main());

Now suppose the C compiler uses a C++-style "name mangling" scheme
in order to distinguish between main(void) and main(int, char **).
The former compiles to 0$main$ and the latter to 2$i$ppc$main$.
At link time, this less-typical box scans the object files to see
whether the "main" symbol is 0$main$ or 2$i$ppc$main$, so as to
choose the correct call into main().

If you write something other than one of these two forms, then, your
program might fail to link.

Suppose that, instead of (or in addition to) name-mangling, we have
a stack-oriented machine in which main()'s return value is popped
and pushed (or no-op'ed) from the value stack to be passed to
exit(). If the value stack is empty at the initial call to main(),
and you use "void main()" (and if the compiler is doing name-mangling
you somehow manage to make it link despite not finding the right
name), then the startup routine's call to exit() (or exit() itself)
attempts to pop a value off an empty stack. The result is a runtime
exception when main() returns.

The latter may sound farfetched, but something remarkably similar
does happen on real implementations today if you manage to write code
of the form:

struct S { char a[100]; };

struct S main(int argc, char **argv) {

Typically one writes this accidentally, by mistakenly leaving off
the ";" at the end of the first line, and using "default int"
declarations that turn out not to be default int after all:

struct S {
char a[100];
} /* NOTE MISSING SEMICOLON */

main(int argc, char **argv) {
... code here using argc and/or argv ...
}

In this case, a number of compilers assume you "really meant":

void main(struct S *__secret_arg1, int argc, char **argv) {
...
/* returning a value assigns to *__secret_arg1, then returns */
}

so that argc and argv wind up having "peculiar values". (In fact,
on these systems today, argv seems to be junk or to contain the
environment variable list, and argc is some huge number. Yes,
I have debugged just such a problem. :) )

The point of all this is simple enough: if you write "int main()",
a big guy with a large bat is metaphorically standing right behind
your compiler-vendor, ready to whack him in the head if he makes
your code fail because of this. But, if you write "void main()",
the guy with the bat will not do anything to your compiler-vendor,
because you failed to keep *your* part of the bargain.

The "bargain" in question is the C standard, which has lists of
programming constructs and behaviors and says (not quite literally)
"if you do only these things, your vendor must do only those things."
As long as the things you need done are things *every* ANSI-C vendor
*must* do, you have little to lose by sticking to the standard.
You may or may not think you have much to gain, but history suggests
that in fact you *do* have something to gain.

In other words, if you write "int main()", you are quite probably
helping yourself, and if you write "void main()", you are quite
probably hurting yourself.

Note that this is *not* true for *other* places you (as a programmer)
might completely ignore the ANSI C standard. For instance, given
that this thread is (for some mysterious reason) cross-posted to
rec.games.chess.computer, you might have a chess game in which you
want to draw graphics in a window. ANSI C does not give you a way
to do this -- so the cost/benefit equation now swings heavily the
other way: "Cost of not using standard C: unknown, probably not
zero but probably not huge. Benefit: can achieve goal." Compare
that to "void main": "Cost: unknown, probably not zero but probably
not huge. Benefit: none."
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://67.40.109.61/torek/index.html (for the moment)
Reading email is like searching for food in the garbage, thanks to
spammers.
 

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,077
Messages
2,570,566
Members
47,202
Latest member
misc.

Latest Threads

Top