3
#include <stdio.h>
   /* print Fahrenheit-Celsius table
       for fahr = 0, 20, ..., 300 */
main()
   {
     int fahr, celsius;
     int lower, upper, step;
     lower = 0;
     upper = 300;
     step = 20;
     fahr = lower;
     while (fahr <= upper) {
         celsius = 5 * (fahr-32) / 9;
         printf("%d\t%d\n", fahr, celsius);
         fahr = fahr + step;
    } 
}

based on the above code I can't understand how you get the below result on the first line. Shouldn't it be 0 -17? This example is on page 17 of the C programming language. I just want to make sure this isn't something to do with older implementations of C, and I'm not getting the same result as the book because I'm using a more current compiler.

1    -17
20   -6
40   4
60   15
80   26
100  37
120  48
140  60
160  71
180  82
200  93
220  104
240  115
260  126
280  137
300  148
Lundin
  • 195,001
  • 40
  • 254
  • 396
Ravenous
  • 356
  • 1
  • 4
  • 16
  • I get `0 -17` as expected using `clang`. What are you using? Notice all the values are multiples of twenty but for the first, so that's likely an error. – tadman Feb 06 '18 at 18:54
  • I get `0 -17` as well. It is the book that says `1 -17` – Ravenous Feb 06 '18 at 18:55
  • @Ravenous Could you please look at the copyright page and report what edition you have? We now have two people saying that their copies have 0 here. – zwol Feb 06 '18 at 18:59
  • 1
    The [first edition](https://archive.org/details/TheCProgrammingLanguageFirstEdition) (1978) is available online. It says `0 -17.8` due to using `%6.1f` for the formatter part. The version on Amazon (2nd. ed. ANSI, 1988) has `0 -17`. Do you have a bad bootleg copy or what? – tadman Feb 06 '18 at 19:04
  • 2
    The first edition of the Ansi version contains a typo. It says "1" there but the code will compile and print a zero. – Rob Feb 06 '18 at 19:22

2 Answers2

4

Indeed, on the first time through the while loop, fahr has the value 0, and that is what will be printed. This is probably a typo in your edition of the book: we have multiple reports in the comments that other editions have 0 where yours has 1.

You are right to be concerned about old C code behaving differently with newer compilers. However, this program does not have any of the things in it that usually cause problems with newer compilers: no pointer aliasing, no concurrency, no arithmetic overflow, etc. The computation of the first two values of the celsius column does involve integer division with a negative dividend, which was partially implementation-defined prior to C1999; if the book had given -18 and -7 for those values, that would have been why. And modern compilers will issue a warning about the missing return type of main, but that doesn't affect the semantics of the program. (I'm not aware of any modern C compiler that actually issues an error for "implicit int", either in its default mode or in its "strictly conforming to C2011" mode. There's usually a way to tell it to make that particular warning into an error, of course.) None of these issues could have have caused the first value of fahr to be printed as 1.

Please learn from this that you should trust your ability to mentally simulate the execution of a program a little more, but printed books a little less. You would also be well-advised to get a newer C textbook—not just a newer edition of K&R, but an entirely new book, that covers the modern language. I regret to say I don't have any recommendations, though.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • The book has zero. OP is claiming that he is getting 1. – taskinoor Feb 06 '18 at 18:55
  • 1
    @taskinoor I understood it to be the other way around? And OP has now confirmed that in the comments on the question. – zwol Feb 06 '18 at 18:57
  • @taskinoor.: You are confusing me now..that's why rolled back the edit – user2736738 Feb 06 '18 at 18:57
  • 1
    @zwol look like you are right. My edition contains `0` (I just checked), so I thought OP is saying the opposite. – taskinoor Feb 06 '18 at 18:58
  • @coderredoc I don't want to make a stronger statement about the book than "probably" without more information (e.g. that this was changed in a later edition, or acknowledge on an errata sheet). – zwol Feb 06 '18 at 18:58
  • @coderredoc What's the publication date on your copy? If we can confirm that you have a newer copy than OP, that would be enough to say yes this was an error in the book. – zwol Feb 06 '18 at 19:00
  • Aha! The first edition of the Ansi version shows a 1 – Rob Feb 06 '18 at 19:17
  • The gcc compiler in conforming mode (`-std=c11 -pedantic-errors`) gives "error: return type defaults to 'int'". If you just compile as `-pedantic` then gcc issues a warning but builds an executable which is not a conforming program. – Lundin Feb 07 '18 at 12:44
  • "However, this particular program does not have anything in it that would be troublesome" Except division of negative integers which is a well-known issue in C. There is no typo, the book is simply too old to be relevant. – Lundin Feb 07 '18 at 12:48
  • @Lundin `-pedantic-errors` is not the conforming mode. The conforming mode is `-std=c11 -Wall -(W)pedantic`. The -errors suffix is just shorthand for a bunch of -Werror= options. – zwol Feb 07 '18 at 13:06
  • @zwol I'll add the formal reference to my answer. But yeah it is well-known, it was pointed out in the old MISRA-C:2004 among others. – Lundin Feb 07 '18 at 13:09
  • @Lundin I did forget that this was implementation-defined in C89. – zwol Feb 07 '18 at 13:11
  • Regarding conforming mode of gcc: the standard only requires that a compiler displays a diagnostic message to the programmer, if a non-conforming program is encountered. What it does with the binary is not covered with the standard. It is safer not to have it generate an executable if the program does not conform to the C standard. – Lundin Feb 07 '18 at 13:17
  • My point is that GCC's "conforming mode" is what the GCC manual says it is, and that is "-std=c{89,99,11} -Wall -Wpedantic", _not_ "-pedantic-errors". You are free to prefer to use -pedantic-errors yourself, but don't confuse people by contradicting the manual. – zwol Feb 07 '18 at 13:20
0

K&R was written when dinosaurs walked the earth. On pre-standard C and C90, the rounding direction of negative integer division was not well-defined. So you could get different results depending on compiler, it was implementation-defined behavior back in the days. I'm not sure if K&R were even aware of the issue - the book is filled to the brim with reliance on poorly-specified behavior.

This bug in the C language was not fixed until the year 1999, some 20 years after the book was written.


See What is the behavior of integer division?, the answer by schot in particular.

Also see the C99 rationale 6.5.5

In C89, division of integers involving negative operands could round upward or downward in an implementation-defined manner; the intent was to avoid incurring overhead in run-time code to check for special cases and enforce specific behavior. In Fortran, however, the result will always truncate toward zero, and the overhead seems to be acceptable to the numeric programming community. Therefore, C99 now requires similar behavior, which should facilitate porting of code from Fortran to C. The table in §7.20.6.2 of this document illustrates the required semantics.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • This is true but irrelevant; the number under discussion is not the result of an integer division. – zwol Feb 07 '18 at 13:07
  • @zwol Aah, well the 1 vs 0 is indeed not a result of division, my bad. But the code is mighty fishy still, especially at the point when the book was written. What is important to point out here is that K&R cannot be trusted. Not only does it contain typos, but also reliance on implementation-defined behavior. – Lundin Feb 07 '18 at 13:13