cc89kernighan-and-ritchie

Doubts in K&R edition 2


1. 8.2 Page 171 Low Level I/O - Read and Write

    #include "syscalls.h"  
    int getchar(void)  
    {  
        char c;  
        return (read(0, &c, 1) == 1) ? (unsigned char) c : EOF;  
    }  

Casting c to unsigned char in the return statement eliminates any problem of sign extension.

What problem we are talking about here? Why unsigned char exactly? What would happen without the cast unsigned char?

2. A7.4.8 Page 204 Sizeof Operator

When applied to a structure or union, the result is the number of bytes in the object, including any padding required to make the object tile an array: the size of an array of n elements is n times the size of one element

What is meant by to make the object tile an array? We were talking about structure and union and suddenly how did this array appear here? This one surely looks like a typo but I have already checked Errata for K&R for all the queries. So most probably I am missing something or giving my non-native English I am not able to grasp it properly.

3. A7.17 Page 209 Assignment Expressions

One of the following must be true: <snip>; or both operands are pointers to functions or objects whose types are the same except for the possible absence of const or volatile in the right operand.

Please explain with code. Something like int a, b are the two objects having same type. etc.

4. A12.5 Page 232 Conditional Compilation

Text controlled by inactive arms of the conditional is ignored except for checking the nesting of conditionals.

Again, please explain with code.

5. B1.4 Page 247 ungetc(int c, FILE *stream)

Only one character of pushback per stream is guaranteed.

Does that mean I can use ungetc for only once in a program/software?

6. B.1.1 Page 242 File Operations

int rename (const char *oldname, const char *newname)

rename is a stdio library routine then why it's not in man -s3 rename but in man -s2 rename? I am using Ubuntu 13.10 BTW.


Solution

    1. If EOF is defined as -1, and if in this compiler implementation the char is by default signed (it is implementation defined whether an unqualified char is signed or unsigned; and GCC even allows changing it for many targets with -funsigned-char/-fsigned-char), then without casting to (unsigned char), reading byte 255 would be indistinguishable from end-of-file.

    2. The object tiling an array means that you have:

      struct foo {
          int a, b;
          char c;
      };
      struct foo bar[5];
      

      That is, array of structs; the size of the whole array is sizeof(struct foo) multiplied by number of elements in the array; and corollary, if there are alignment requirements, the sizeof(struct foo) must take these into account. On this computers int is 4 bytes and char 1; yet the structure has size of 12 bytes (sizeof(struct foo) == 12); and the size of array is exactly sizeof(struct foo) * 5, not sizeof(struct foo) * 5 + some.

    3. As I understood this, it means that, all previous ones in that paragraph failing, a pointer is assignable from another, if the types are exactly the same, or the left hand pointer qualifies the pointed-to type with volatile or const that is not present on the right hand type:

      int a = 42;
      const volatile int *b = 0;
      b = &a;
      

      is ok; as the left hand size has type const volatile int * whereas the right hand side is int *; it is OK that const and volatile are absent on the RH, wheras

      const volatile int a = 42;
      int *b = 0;
      b = &a;
      

    is not ok, because the left hand side is int * and RH has type const int *; such assignment would discard qualifiers; gcc emits a warning:

    warning: initialization discards ‘const volatile’ qualifier from pointer target type [enabled by default]

    1. it means that if you have

      #if 0
      
      // this is the inactive arm of #if
      // the code here is ignored *except* for checking
      // for closing #endif; and #if/#ifdef for nesting
      
      #if 0
      #endif // so that the preprocessor knows that this #endif
             // does not yet end the inactive arm of #if 
      
      #else
      // but here is an active arm
      #endif
      
    2. An ungetc must be followed by at least 1 read; it is not guaranteed that you can do ungetc successfully right after another ungetc.

    3. Everything that comes directly from a Linux system call is in manual section 2. rename is a system call, though it also does conform to C89, C99.