F
Falcon Kirtarania
You might try putting it over a Z80 running on a 233MHz clock.
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.
Falcon said:Christian Bau said: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?
Christian Bau said: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?
Falcon said: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.
BTW, aren't all implementation-specific extensions such as the Windows
API also undefined behaviour?
The relevance is intact, because the MS Visual Studio C++ .NET compiler will
also compile C.
Joona I Palaste said:Richard Heathfield <[email protected]> scribbled the following
[Followups set to comp.lang.c]Falcon Kirtarania wrote:Feel free to write a C compiler which diagnoses any and all instances of
undefined behaviour. Consider whether it should generate a diagnostic for
this code. If so, why? If not, why not?int foo(int *a, int *b)
{
return *a = *b++;
}<snip>
Well, I believe that the problem here could be solved by using run-time
checks for undefined behaviour. That would make the generated code quite
slow, but it would still work correctly.
Then, if we want to achieve what Falcon is suggesting, let's leave the
definition of undefined behaviour as it is, and instead change the
standard from saying "such and such results in undefined behaviour" to
"such and such results in an error". Whether we *do* want to achieve it
is another question.
Richard Heathfield said:Joona I Palaste wrote:
Depends on your definition of "undefined". Personally, I agree that
extensions effectively invoke undefined behaviour.
When adding extensions to lcc-win32 I have followed explicitly
undefined behaviour to avoid being incompatible with existing code.
For instance this extension is undefined behavior in standard C:
/* Define a new operator addition for a user defined type of numbers */
int operator+(Number a,Number b) { ... }
No legal program can use that, so it is a compatible extension. I took
pains that
int operator = 5;
still works, of course.
As far as the standard goes, extensions are not forbidden. They just
should not introduce new keywords in contexts where they would
invalidate existing code. Existing code that writes standard C like:
int operator = 5;
should always compile what is intended.
More difficult to follow was __int64 for long long. In this case
lcc-win32 added
#define __int64 long long
automatically at startup to be able to compile code that uses that symbol.
Since it wasn't in the legal namespace anyway I think it is OK.
More problematic were the windows API headers. They are huge, and
lcc-win32 was forced to provide an ANSI C version, avoiding the dreaded
asm { /* a lot of assembly in microsoft syntax */}
that polluted so many headers. This has gotten better now, and many
SDK headers are compliant. Still, sometimes I wonder what does it mean:
typedef struct tagWindowsStruct {
...
DWORD bitfield:2;
}
a DWORD is an unsigned long, what really doesn't fit into 2 bits...
Why not use
unsigned bitfield:2;
to detect at compile-time or runtime? 'foo main', where 'foo'!='int',
looks easy to me. I can't think of any others off the top of my
head.
Richard said:Joona I Palaste wrote:
Depends on your definition of "undefined". Personally, I agree that
extensions effectively invoke undefined behaviour.
I seem to recall that some people disagree with me.
The name "Doug Gwyn" springs to mind, but I
may have disremembered.
pete said:[...] Personally, I agree that
extensions effectively invoke undefined behaviour.
I seem to recall that some people disagree with me.
The name "Doug Gwyn" springs to mind, but I
may have disremembered.
The consensus of comp.std.c,
was that a program which calls a clear screen function
exhibits behavior which is not defined by the standard,
and which is also not considered to be undefined behavior.
I don't understand the importance of the distinction.
Falcon said:Theoretically, any undefined behavior should return an error (as in, the
standard should change). This might help solve the troubles of awful
programming.
]
when
their
platform.
void
Good question. Having a main () function declared as "void main ()"
invokes undefined behavior. That means that according to the C Standard,
anything could happen. And when I say anything, I mean _absolutely
anything_. If you compile and run this program:
void main () { printf ("Hello, world\n"); }
then it could happen that your computer explodes, or your harddisk gets
formatted, and you can't complain that your compiler is not a Standard C
compiler. (You still can complain that a common mistake like that
shouldn't explode your computer, but you can't complain that the
compiler is not conforming to the C Standard. )
You can check the documentation for your compiler. Maybe it defines what
will happen; if the C Standard leaves something undefined then any
compiler is allowed to define it. Maybe your compiler refuses to compile
the program; I would say that would be a very sensible approach. Maybe
your program crashes as soon as you start it, maybe it crashes just when
it finishes. Maybe the operating system puts up an alert that says:
"Warning: Program xxxx seems to be broken. Please contact the
manufacturer of this program for further advice. ". Anything could
happen.
Falcon said:Theoretically, any undefined behavior should return an error (as in, the
standard should change). This might help solve the troubles of awful
programming.
]
when
their
platform.
void
Good question. Having a main () function declared as "void main ()"
invokes undefined behavior. That means that according to the C Standard,
anything could happen. And when I say anything, I mean _absolutely
anything_. If you compile and run this program:
void main () { printf ("Hello, world\n"); }
then it could happen that your computer explodes, or your harddisk gets
formatted, and you can't complain that your compiler is not a Standard C
compiler. (You still can complain that a common mistake like that
shouldn't explode your computer, but you can't complain that the
compiler is not conforming to the C Standard. )
You can check the documentation for your compiler. Maybe it defines what
will happen; if the C Standard leaves something undefined then any
compiler is allowed to define it. Maybe your compiler refuses to compile
the program; I would say that would be a very sensible approach. Maybe
your program crashes as soon as you start it, maybe it crashes just when
it finishes. Maybe the operating system puts up an alert that says:
"Warning: Program xxxx seems to be broken. Please contact the
manufacturer of this program for further advice. ". Anything could
happen.
...
The standard just says int/unsigned int as possible types for a bit field.
I added long/unsigned long, short, and even char. This makes the compiler
more usable but strictly speaking the standard says int/unsigned.
Yes, but "unsigned" would do the trick too... And since you are specifying
the number of bits, there are no 64 bit portability issues!
Falcon Kirtarania said: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.
Alexander Grigoriev said:My favorite example of a crappy compiler is GNU ARM C/C++ compiler. We've
had so many problems with it, and it's slow as molassa.
One time, for example, it just didn't complain about a global pointer,
_defined_ in multiple compilation units, and _twice_ defined in one of them,
for example:
struct A * pa;
struct A * pa=& a;
Second definition just didn't have any effect,
without any diagnostics. Of
course, the first definition should have been a declaration, with 'extern',
but the compiler didn't give any help to find it.
When I've tried MS eVC ARM C, I thought it's godsent.
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.