Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Mark <spam@xxxxxxxxxxxxxxxxxxxxxx>
- Date: Fri, 13 Mar 2009 11:28:32 +0000 (UTC)
Apologies - this conversation is really for the anoraks. It just
happens to be my professional area, so I can't resist...
Frank Adam <fajp@xxxxxxxxxxxxxxxxxxxxxxxx> wrote:
On Fri, 13 Mar 2009 08:54:42 +0000 (UTC), Mark
<spam@xxxxxxxxxxxxxxxxxxxxxx> wrote:
Frank Adam <fajp@xxxxxxxxxxxxxxxxxxxxxxxx> wrote:
void PrintIan()
{
char* s1 = "Ian ";
char* s = calloc(4);
for(int i = 1;i<4;i++)
*s[i] = *s1[i];
printf("%s", s);
}
What did i just tell the PC, what was my intention and what is the
output ? Should i leave it ?
How pedantic do you want me to be?
As you haven't called PrintIan, you (arguably) have only asked for a
void-returning function to be defined. ;-)
LOL. Well you know how it is, bugs really do multiply. :)
Oh, yes.
I have also just realised that I also ignored the fact that your calloc
call is broken. 'calloc' requires two arguments (number of members and
size of element), so it should be:
char* s = calloc(4, sizeof(char));
Though char will always be one byte*, so this would do:
char* s = calloc(4, 1);
* I know they talked about widening it, but they won't. It breaks too
many things, and now we have wide chars for internationalisation, I
suspect char will forever be a byte. That may already have been decided
(I can't be bothered to look it up).
What you asked this function to be capable of doing depends on whether
you're asking what is written in the language or what the compiler asked
the computer to do? Optimisation and implementaion means there is a
very wide spectrum of behaviours which would be C99/C++* conformant.
* I'm not totally clear which language you're using - though I'm
assuming C99 based on: the lack of casting for calloc and the use of
calloc and printf which are not normally used in (good) C++, and the
locally-scoped 'i' which isn't legal in pre-C99 C.
Overall, the whole thing could be optimised away (as it does nothing)
or, at the other extreme, it could:
Optimisers have become very clever indeed, so we'll have that turned
off for this exercise.. mmmmk ? :-)
Okay - I _did_ warn you I was being pedantic. Earlier in my career, I
spent five years lecturing on introductory programming in C++ to CS
undergraduates. ;-)
Plus, I said they "could" rather than they "would". I'm describing what
the standard allows.
There _are_ some very clever optimisers now and, if they did all of that
optimisation, I wouldn't be shocked. Most won't manage all of it, though.
* allocate s1 and s on the stack with a static string of 8 printable
characters plus '\0' which s1 points to (precisely where that goes
is implementation-dependent).
Um.. is that something in the new(C9x) standard ? As i recall
ANSI/ISO(certainly pre-C9x) would have made that 3 printable plus a
required Nul to form a correct and printable C string.
I'm referring to this:
char* s1 = "Ian ";
char* s = calloc(4);
I'm ignoring the calloc call at this stage (as it involves a function
call which happens later than the stack instantiation), and
concentrating on this[2]:
char* s1 = "Ian ";
char* s;
There are (possibly[1]) three chunks of stack being defined (size of the
pointer is implementation-specific - often 4 or 8 bytes on 32 and 64 bit
architectures respectively):
name type size contents
(bytes)
s1 char * ?? address of the anonymous array of chars below
s char * ?? set (later) to value returned by calloc
anonymous char 9 'I', 'a', 'n', ' ', ' ', ' ', ' ', ' ', '\0'
Because you have specified a C string with "Ian" followed by five
spaces, it will allocated 8 characters plus space for a '\0' as above.
Does that make sense? That's been true since pre-ansi C (showing my age
again).
1. The static C string could be allocated a number of
implementation-specific ways.
2. Being an old C programmer, I'd attach the '*' to the variable name:
char *s1 = "Ian ";
The '*' is a modifier rather than anything else. New programmers
take the C++ style (above) to make the type be "char*". Unless you
never have more than one declaration together, this is misleading as:
char* a, b;
defines one "char *" and one "char" (a and b respectively). The
older, traditional C style:
char *a, b;
makes that _much_ clearer, IMO.
* It allocates 4 bytes from the heap, zeroes them (as it's calloc)
and has 's' point at them.
* You locally allocate 'i' for a loop over the values 1, 2 and 3,
assigning the relative elements pointed to by s to the equivalent
pointed to by s1. This leaves the newly allocated memory
containing "\0an "
Correct.
* You ask printf to print the string represented by the memory
pointed to by 's'...which is a zero-length string due to it
starting with a null character.
Yup.
Any or all of those will be identified as pointless by a good optimising
compiler. In a full program, the compiler might even optimise away the
function call in its entirity whilst the program remains
standards-compliant.
I can't possibly know what you intended, but if it was to print "Ian"
you would probably do something closer to a single printf/puts*...but if
you wanted to get that program working, you'd do something like change
the '1' to a '0'.
Mark, the 1 was the intentional bug, to show Ian what a simple bug
does to an otherwise properly laid out process. The code is obviously
made to do something much more laborously than how you or I would
write it in real life. I could have made an even longer winded one to
expose it for all it is worth,
No - I realised what you were doing. It's the classic mistake (along
with running one beyond the end of an array) that new programmers
(particularly, in days of yore, when they were used to Fortran) made
when first programming in C or C++.
but i was sure Ian would understand. As
it is, i doubt he did.
He does make a good point, though. Rules are often limits rather than
instructions. A bit like the C standard where large sections are to do
with what you aren't allowed to do rather than specifically telling you
what you must do e.g. you are allowed to optimise away this instruction:
int i;
i = 7; /* this assignment doesn't have to actually happen */
i = 23; /* because this one clearly undoes it before its used */
whilst remaining conformant, but you are not required to optimise it
away. Rules are rarely prescriptive or we really would innovation
stifled.
Language segments, however, are not really as prescriptive as people
think. Not only do you have compiler designers getting in the way, most
programmers get through life not realising just how much reordering of
instructions goes on, particularly at a CPU-level. Without explicit
barriers (which, in most high-level languages are not available), the
average programmer thinks things are going on in a far more
straightforward way than they actually are. This is even more true when
it comes to concurrent programming (which, with multi-core computing, is
now the norm). Without care, computer programs are hints. The only
requirement is that the end-result is equivalent; even when you're quite
explicit about the route to take, a lot of languages have massive
latitude about changing the route so long as the destination is not
affected.
Unanticipated behaviour is, therefore, very common - not least because
most people learn this stuff through example. In that respect and in
the respect that a computer language doesn't directly translate to
behaviour (an instruction isn't really an instruction), your analogy
holds up rather better than Ian acknowledges.
Having agreed with you both once each, I'll now agree with you both
simultaneously: whilst many (most) rules are designed as limitations,
some are designed such that it leaves only one possible course of action
and, therefore, are equivalent to instructions.
There - am I sat on the fence adequately firmly yet? ;-)
A funtion usually creates a rule. The instructions within the function
instruct the computer in how that rule is to be enforced. The bug,
makes the whole rule fail unless it is fixed. Which connects it to how
the FIA rule having a loophole and how not acting on it makes that
rule fail just the same.
Now for the pedantic bits. :)
Calloc wasn't cast, because i forgot. Let's assume we were using
Borland 4.2 with ANSI/ISO confirmance turned off. :)
Whoa...
calloc _shouldn't_ be cast (as of C90/ISO 9899:1990, and certainly not
now). The only time it's always valid, is in C++. Why? C90 introduced
"void *" which, being compatible (and automatically and safely
promotable to any other pointer) doesn't require casting...except in C++
which (inexplicably) has never adopted "void *". Whilst casting isn't
necessarily wrong, it can hide bugs.
Suppose you write a piece of code and forget to include stdlib.h
Your code segment looks like:
char *blah = (char *)calloc(443, sizeof(char));
potentially, you have a major bug. Why? Because you have no prototype
for calloc, and C defaults to functions returning an int. If you are
lucky (and you often will be lucky), an int is the same size as a
pointer on your architecture (32 bit linux and Windows were like this
for a long time). Older timers like me remember architectures where
this wasn't the case, so now you have the return value from calloc being
compressed to 32 bits and then expanded again. Unless the lost bits
happen to have been zero _and_ the reconstructed pointer is kept in the
same place (no rearrangement of bytes), you now have gibberish. There
have been a _lot_ of programs (and OSs) that needed this kind of bug
fixed in the move from x86 to x86_64 (where the int is 32 bits and the
pointer is 64).
If you left out the cast, the compiler tells you you've no prototype and
you get to fix it. With the cast, it silently coerces the pointer and
you have undefined behaviour and, potentially, a bug.
That declaration of the int inside the for loop is inexcusable though.
I hang my head in shame for that, as i(and most others) would have
flamed the hell out of people doing that on the C_Echo.
Whereas this is fully supported in C99 (and as an extension to a lot of
non-C99 C compilers) these days.
* Given we're really talking about a single static string, use of printf
is a little pointless, and puts (or even write, if use of buffered
output isn't that important) is sufficient.
Come on, reinventing the wheel has always been the best way of
learning to code. :-)
Heh! ;-)
.
- Follow-Ups:
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Frank Adam
- Re: Briatore hits out on 'cheating' by 'certain' teams
- References:
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: AC
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Frank Adam
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Ian Rawlings
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Frank Adam
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Ian Rawlings
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Frank Adam
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Ian Rawlings
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Frank Adam
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Ian Rawlings
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Frank Adam
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Mark
- Re: Briatore hits out on 'cheating' by 'certain' teams
- From: Frank Adam
- Re: Briatore hits out on 'cheating' by 'certain' teams
- Prev by Date: English sheep-shaggers 'n' Northern monkeys (McLaren)
- Next by Date: Re: Quiz question
- Previous by thread: Re: Briatore hits out on 'cheating' by 'certain' teams
- Next by thread: Re: Briatore hits out on 'cheating' by 'certain' teams
- Index(es):
Relevant Pages
|