Re:C Programming Puzzlers
by psykotic on Saturday February 25, 2012 @02:44PM
(#3633667)
Puzzles 9 and 12 assume sizeof(int) is 2. It's poor form for a language lawyering quiz to make an assumption about implementation-dependent behavior. It's especially poor form when the assumption made is long outdated and likely to surprise--I suppose it's still true for C compilers targeting 8-bit and 16-bit microcontrollers.
Aside: I remember buying the first Programmer's Heaven CD-ROM boxed set at The Party back in the mid-nineties. It was an incredibly valuable resource for me in those days. The best source of programming information was through the dial-up BBS scene, but none of the boards I frequented had a collection on the scale of Programmer's Heaven.
Re:C Programming Puzzlers
by X-Istence on Saturday February 25, 2012 @02:54PM
(#3633692)
From question 9:
"What is the output of this program on an implementation where int occupies 2 bytes?"
Question 12 is a function pointer question and doesn't say anything about ints at all.
I'll assume you meant Question 14:
"What is the output of this program on an implementation where int and all pointer types occupy 2 bytes?"
If you read the question you would have noticed that the assumption was put in writing so that even if you first assumed int was 4 bytes, or pointers were 4 bytes you would still be able to find the answer correctly.
Re:C Programming Puzzlers
by finnw on Saturday February 25, 2012 @03:18PM
(#3633747)
Was it possible to initialise a local array with literals like that (e.g. Q5) in C89? If not then the version of C in the examples (assuming it is consistent) must be at least C99, which suggests that sizeof(int)==2 is due to the target being an embedded device rather than the program being old.
Edit: clarified that I am referring to local arrays only
Re:C Programming Puzzlers
by tjoff on Sunday February 26, 2012 @04:01AM
(#3635192)
A char might always be one byte but one byte isn't necessarily 8 bits.
I'm often puzzled by the fact that the size of basic datatypes isn't platform independent.
If I need to count to x I, more often than not, need to count to x on all platforms. Yet for some reason that is something that varies on platform.
Yes, there are of course times when this is useful but that should be the exception (right?). And apparently the industry is on my side on this by making the situation even worse and saying that an integer on a 64 bit x86-machine should be 4 bytes. Now the sizes of the datatypes not only vary by platform but they also have nothing to do with the underlying hardware architecture either. It's just some arbitrary number that is different on platforms just for the sake of giving you a headache. Thanks?
Of course a large datatype, x, might incur a severe performance penalty on platform y but just changing the size of x behind my back is not constructive.
Re:C Programming Puzzlers
by jleader on Sunday February 26, 2012 @08:17PM
(#3637395)
I think the idea originally was that int would usually be the preferred "natural" size for arithmetic on any given platform. Longer sizes are available when you need greater range, and smaller sizes are available when you're trying to conserve memory, but both may be slower than int (because of the possible need for multiple-word arithmetic in the longer sizes, and the possible need for sub-word operations in the smaller sizes).
So int is for things like loop indices, where efficiency of arithmetic is more important than size in memory.
Re:C Programming Puzzlers
by Sniffnoy on Saturday February 25, 2012 @03:54PM
(#3633830)
Checking the rules for array initialization in Harbison & Steele, this does indeed seem to be invalid. I'm surprised, I actually thought that was valid...
Re:C Programming Puzzlers
by cygx on Saturday February 25, 2012 @03:41PM
(#3633802)
See C99 6.5.6 §7:
For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
Re:C Programming Puzzlers
by grannyg00se on Saturday February 25, 2012 @05:32PM
(#3634040)
Stopped at #3. It seems incorrect. The answer states that foo returns x to the power of n. But I ruled that answer out since any 0 or negative n is going to return 1.
Re:C Programming Puzzlers
by tzs on Sunday February 26, 2012 @02:57AM
(#3635112)
Returning 1 for n = 0 is OK, as x^0 = 1 for all non-zero x, and 0^0 is usually also defined as 1.
However, as you note, it also returns 1 for negative n, and that is just wrong.
Well, wait a second....actually, if it were a machine where integer division rounds up[1], so that 1/k = 1 for k > 1, then #3 would correctly compute x^n for n < 0. Does this safe the author's answer?
Nope!
Their code for n > 0 would fail on such a machine. They are relying on repeated division by 2 eventually resulting in 0 in order to terminate the recursion. On a round up machine, repeated division converges to 1, not 0.
[1] I'm assuming that rounding behavior of integer division is implementation defined in C as defined at the time that quiz was written.
Re:C Programming Puzzlers
by furyofantares on Wednesday February 29, 2012 @01:49AM
(#3646795)
My point was just that if you want to nitpick that it isn't x^n for all inputs, then the n < 0 cases are only a part of the problem since foo(10,10) can't possibly be 10^10 regardless of the the function's body.
I'm not sure what you want me to propose a fix for. If we want a function that calculates x^n we'd probably wouldn't write it anything like this, and we would probably return a double and accept some inaccuracy.
Presumably what we actually want is an example of a hard to read function that calculates a simple result so we can use it on an amusing quiz. In that case we could change it to take unsigned n and ask what it computes in the cases where there isn't overflow. Or even better, it would be neat if there is a reasonably small modification that could be made so that it would calculate x^n mod (2^32-1).
Re:C Programming Puzzlers
by prodigal_erik on Sunday February 26, 2012 @06:40PM
(#3637179)
There's no http://en.wikipedia.org/wiki/Sequence_point between the two increments, so the standard allows the compiler to do pretty much anything, even http://catb.org/jargon/html/N/nasal-demons.html. The way I've heard it, these operators were added to take advantage of pre- and post-increment hardware support in the PDP-11 (forty years ago!), and everyone just knew what would happen, but ANSI later wanted compilers to have enough latitude to take advantage of other hardware which behaves differently.
Re:C Programming Puzzlers
by vainguard on Sunday February 26, 2012 @08:55PM
(#3637473)
Just when I thought (after completing the puzzles) that C is reasonably reasonable language, I learn that the execution order of 'f()+g()' is unspecified. Wow!
Re:C Programming Puzzlers
by gue5t on Saturday February 25, 2012 @02:58PM
(#3633703)
These are not the problem with C. Things like a lack of support for functional programming constructs and more powerful manipulation of structs (e.g. iterating over fields and inspecting variable types) would be much more improvement to C than minor cosmetic changes that would hide the details that this quiz asks about.
Aside: I remember buying the first Programmer's Heaven CD-ROM boxed set at The Party back in the mid-nineties. It was an incredibly valuable resource for me in those days. The best source of programming information was through the dial-up BBS scene, but none of the boards I frequented had a collection on the scale of Programmer's Heaven.
"What is the output of this program on an implementation where int occupies 2 bytes?"
Question 12 is a function pointer question and doesn't say anything about ints at all.
I'll assume you meant Question 14:
"What is the output of this program on an implementation where int and all pointer types occupy 2 bytes?"
If you read the question you would have noticed that the assumption was put in writing so that even if you first assumed int was 4 bytes, or pointers were 4 bytes you would still be able to find the answer correctly.
Yes, I meant question 14, not 12.
Edit: clarified that I am referring to local arrays only
Also, let's not forget what the C standard says about integer sizes, which is that
A) It is guaranteed that sizeof char == 1
B) It is guaranteed that the following holds true: sizeof char <= sizeof short <= sizeof int <= sizeof long
So it's always completely unrealistic to assume anything about the size of these types on any system, except for the guarantee in (A)
I'm often puzzled by the fact that the size of basic datatypes isn't platform independent.
If I need to count to x I, more often than not, need to count to x on all platforms. Yet for some reason that is something that varies on platform.
Yes, there are of course times when this is useful but that should be the exception (right?). And apparently the industry is on my side on this by making the situation even worse and saying that an integer on a 64 bit x86-machine should be 4 bytes. Now the sizes of the datatypes not only vary by platform but they also have nothing to do with the underlying hardware architecture either. It's just some arbitrary number that is different on platforms just for the sake of giving you a headache. Thanks?
Of course a large datatype, x, might incur a severe performance penalty on platform y but just changing the size of x behind my back is not constructive.
So int is for things like loop indices, where efficiency of arithmetic is more important than size in memory.
---
I'm a bit rusty on the C spec, but I think the author is wrong about #4.
The answer refers to an exception for a pointer that points one past the end of an array.
And &a[5] would be valid based on that rule, because it points one past the end of the array a.
However (&a + 1) is not valid. It does not point one past the end of an array (because although a is an array, it is not an element of an array.)
Having said that I would be surprised if any compiler gave a result other than "2 5". Still, it's technically undefined.
For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
edit: added emphasis
However, as you note, it also returns 1 for negative n, and that is just wrong.
Well, wait a second....actually, if it were a machine where integer division rounds up[1], so that 1/k = 1 for k > 1, then #3 would correctly compute x^n for n < 0. Does this safe the author's answer?
Nope!
Their code for n > 0 would fail on such a machine. They are relying on repeated division by 2 eventually resulting in 0 in order to terminate the recursion. On a round up machine, repeated division converges to 1, not 0.
[1] I'm assuming that rounding behavior of integer division is implementation defined in C as defined at the time that quiz was written.
I'm not sure what you want me to propose a fix for. If we want a function that calculates x^n we'd probably wouldn't write it anything like this, and we would probably return a double and accept some inaccuracy.
Presumably what we actually want is an example of a hard to read function that calculates a simple result so we can use it on an amusing quiz. In that case we could change it to take unsigned n and ask what it computes in the cases where there isn't overflow. Or even better, it would be neat if there is a reasonably small modification that could be made so that it would calculate x^n mod (2^32-1).