Hendeca
Posts: 3
Joined: Fri Apr 29, 2016 5:08 am

Strange behavior of EOF in raspbian

Fri Apr 29, 2016 5:45 am

Hello All!

I have a Raspberry Pi 2 v1.1 with Raspbian and I'm working through some of the exercises in K&R's The C Programming Language. I'm finding that the terminal handles EOF very strangely.

I was doing problem 1-22 from the book (not really that important which exercise it is) and the program loops through an input stream until EOF like many exercises in the book. However, I found that when I pipe the contents of a text file to the program (using cat), it endlessly prints a strange question mark character when it encounters EOF. I've also tried just typing in input and pressing ctrl + D for end of file. However instead of ending the program, it prints one of the question mark characters for each time I press ctrl + D.

I tried creating a program that just prints the EOF character, and it was that strange question mark character once again (basically looks like a white diamond with a black question mark in the middle). I tried the same program on my mac and it performed fine and as expected. I compiled using gcc first, then cc.

Does anyone have any idea why the terminal is handling EOF in this fashion? Thank you!

User avatar
RaTTuS
Posts: 10381
Joined: Tue Nov 29, 2011 11:12 am
Location: North West UK

Re: Strange behavior of EOF in raspbian

Fri Apr 29, 2016 7:14 am

it is probably not an EOF
is this on the machine itself or via ssh
can you post the code here [use code blocks]
How To ask Questions :- http://www.catb.org/esr/faqs/smart-questions.html
WARNING - some parts of this post may be erroneous YMMV

1QC43qbL5FySu2Pi51vGqKqxy3UiJgukSX
Covfefe

User avatar
PeterO
Posts: 4879
Joined: Sun Jul 22, 2012 4:14 pm

Re: Strange behavior of EOF in raspbian

Fri Apr 29, 2016 7:43 am

Hendeca wrote: (not really that important which exercise it is)
It is vitally important. Crystal balls are notoriously unreliable at guessing source code :D
PeterO
Discoverer of the PI2 XENON DEATH FLASH!
Interests: C,Python,PIC,Electronics,Ham Radio (G0DZB),1960s British Computers.
"The primary requirement (as we've always seen in your examples) is that the code is readable. " Dougie Lawson

User avatar
AndyD
Posts: 2331
Joined: Sat Jan 21, 2012 8:13 am
Location: Melbourne, Australia
Contact: Website

Re: Strange behavior of EOF in raspbian

Fri Apr 29, 2016 8:40 am

It would be good to see your code, but I think I can guess what the problem is. A common error is writing code like the following:-

Code: Select all

#include <stdio.h>

int main(void)
{
    char c = 0;

    while ((c = getchar()) != EOF)
    {
        putchar(c);
    }

    return 0;
}
It looks OK, but it has a subtle bug that will only show up on systems where the char type is signed by default. On the Raspberry Pi, the char type is signed, on many other systems it is unsigned. The value of EOF is -1 (on most systems). On the Raspberry Pi, when the char type is signed in the code above, if getchar() returns EOF, the value assigned to c is 255 and the comparison is always true. The problem is that getchar() actually returns an int (and putchar()'s single argument is an int also). So the code should be:-

Code: Select all

#include <stdio.h>

int main(void)
{
    int c = 0;

    while ((c = getchar()) != EOF)
    {
        putchar(c);
    }

    return 0;
}
Sadly, gcc doesn't pick up the issue in the first version of this code, even when you ask for all warnings (-Wall). The clang compiler does pick it up

Code: Select all

 warning: comparison of constant -1 with expression of type 'char'
      is always true [-Wtautological-constant-out-of-range-compare]
    while ((c = getchar()) != EOF)
           ~~~~~~~~~~~~~~~ ^  ~~~

jahboater
Posts: 4595
Joined: Wed Feb 04, 2015 6:38 pm

Re: Strange behavior of EOF in raspbian

Fri Apr 29, 2016 9:49 am

It looks OK, but it has a subtle bug that will only show up on systems where the char type is signed by default. On the Raspberry Pi, the char type is signed, on many other systems it is unsigned. The value of EOF is -1 (on most systems). On the Raspberry Pi, when the char type is signed in the code above, if getchar() returns EOF, the value assigned to c is 255 and the comparison is always true. The problem is that getchar() actually returns an int (and putchar()'s single argument is an int also). So the code should be:-
I think char is unsigned on the Pi (because the ARM instruction set cannot directly do signed arithmetic on 8 bits, unlike x86). As you say, the int value from getchar() gets truncated to 255 and, because the char is unsigned, never gets sign extended back again for the comparison. Try -fsigned-char on the Pi.

User avatar
jojopi
Posts: 3078
Joined: Tue Oct 11, 2011 8:38 pm

Re: Strange behavior of EOF in raspbian

Fri Apr 29, 2016 10:42 am

AndyD wrote:Sadly, gcc doesn't pick up the issue in the first version of this code, even when you ask for all warnings (-Wall).
Despite the name, -Wall does not enable all warnings. "gcc -Wall -Wextra" turns on more warnings, including this one.

Some of the constructs that gcc can warn about are considered sufficiently useful or difficult to avoid that they are included neither in -Wall nor -Wextra, but require their own -Wxxxxx.
jahboater wrote:Try -fsigned-char on the Pi.
That just gives a different bug. Every char value is a valid return from getchar(), and EOF is an additional non-char value. Whether char is signed or not, we need a wider type. (K&R does explain this.)

jahboater
Posts: 4595
Joined: Wed Feb 04, 2015 6:38 pm

Re: Strange behavior of EOF in raspbian

Fri Apr 29, 2016 10:51 am

jojopi wrote:
jahboater wrote:Try -fsigned-char on the Pi.
That just gives a different bug. Every char value is a valid return from getchar(), and EOF is an additional non-char value. Whether char is signed or not, we need a wider type. (K&R does explain this.)
Agreed, most definitely "c" should be declared as "int".
I just mentioned -fsigned-char to illustrate the point that it is the signed or unsigned nature of char that caused the change in behaviour across platforms. Sorry for the brevity.

Hendeca
Posts: 3
Joined: Fri Apr 29, 2016 5:08 am

Re: Strange behavior of EOF in raspbian

Fri Apr 29, 2016 8:43 pm

AndyD wrote:It would be good to see your code, but I think I can guess what the problem is. A common error is writing code like the following:-

Code: Select all

#include <stdio.h>

int main(void)
{
    char c = 0;

    while ((c = getchar()) != EOF)
    {
        putchar(c);
    }

    return 0;
}
It looks OK, but it has a subtle bug that will only show up on systems where the char type is signed by default. On the Raspberry Pi, the char type is signed, on many other systems it is unsigned. The value of EOF is -1 (on most systems). On the Raspberry Pi, when the char type is signed in the code above, if getchar() returns EOF, the value assigned to c is 255 and the comparison is always true. The problem is that getchar() actually returns an int (and putchar()'s single argument is an int also). So the code should be:-

Code: Select all

#include <stdio.h>

int main(void)
{
    int c = 0;

    while ((c = getchar()) != EOF)
    {
        putchar(c);
    }

    return 0;
}
Sadly, gcc doesn't pick up the issue in the first version of this code, even when you ask for all warnings (-Wall). The clang compiler does pick it up

Code: Select all

 warning: comparison of constant -1 with expression of type 'char'
      is always true [-Wtautological-constant-out-of-range-compare]
    while ((c = getchar()) != EOF)
           ~~~~~~~~~~~~~~~ ^  ~~~
Thank you, this was the problem! I'm a bit new to C, as is probably obvious, but I should have known to post my code by now. Unfortunately the exercise is in the first chapter of the book (called a tutorial introduction) and this point isn't touched upon until later on. I've tested the code with the variable c specified as an int and it now works as expected!

Is it safe to assume that character arrays are still the proper way to store strings? I would assume so since EOF is not generally a character found in a string and since all of the characters one might expect to find in a string would be positive integer values, but then again I am somewhat new to this stuff! I'm really enjoying the book despite the fact that I'm only finishing the introductory chapter. I worked through a large portion of the O'Reilly book Practical C Programming and I can already see that this one is vastly superior (and, ironically, much more practical).

The code, in case anyone was wondering is as follows:

Code: Select all

#include <stdio.h>
#define MAX_COLUMNS 20
#define MAX_TAB 8
#define MAX_LINE 100

int pos = 0;
char c;
char line[MAX_LINE];

void print_to_pos(int pos);
int find_blank(int pos);
int newpos(int pos);
int exp_tab(int pos);

int main() {
	while((c = getchar()) != EOF) {
		line[pos] = c;
		if(c == '\t') {
			pos = exp_tab(pos);
		} else if(c == '\n') {
			print_to_pos(pos);
			pos = 0;
		} else if(++pos >= MAX_COLUMNS) {
			pos = find_blank(pos);
			print_to_pos(pos);
			pos = newpos(pos);
		}
	}
	return 0;
}

void print_to_pos(int pos) {
	int i;
	for(i = 0; i < pos; ++i) {
		putchar(line[i]);
	}
	if(pos > 0) {
		putchar('\n');
	}
}

int exp_tab(int pos) {
	line[pos] = ' ';
	for(++pos; pos <= MAX_COLUMNS && (pos % MAX_TAB) != 0; ++pos) {
		line[pos] = ' ';
	}
	if(pos < MAX_COLUMNS) {
		return pos;
	} else {
		print_to_pos(pos);
		return 0;
	}	
}

int find_blank(int pos) {
	while(pos > 0 && line[pos] != ' ') {
		--pos;
	}
	if(pos != 0) {
		return pos;
	} else {
		return MAX_COLUMNS;
	}
}

int newpos(int pos) {
	int i, j;
	if(pos <= 0 || pos >= MAX_COLUMNS) {
		return 0;
	} else {
		i = 0;
		for(j = pos; j < MAX_COLUMNS; ++j) {
			line[i] = line[j];
			++i;
		}
		return i;
	}
}
This is actually the solution from the answers book. Thank you for your help, I will use int instead of char when using a while loop to loop through an input stream in this fashion.

User avatar
AndyD
Posts: 2331
Joined: Sat Jan 21, 2012 8:13 am
Location: Melbourne, Australia
Contact: Website

Re: Strange behavior of EOF in raspbian

Fri Apr 29, 2016 10:08 pm

Hendeca wrote: Is it safe to assume that character arrays are still the proper way to store strings? I would assume so since EOF is not generally a character found in a string and since all of the characters one might expect to find in a string would be positive integer values, but then again I am somewhat new to this stuff! I'm really enjoying the book despite the fact that I'm only finishing the introductory chapter. I worked through a large portion of the O'Reilly book Practical C Programming and I can already see that this one is vastly superior (and, ironically, much more practical).
Yes, a string in C should be stored in a char array. All the string related functions declared in string.h pass string as char pointers. For example size_t strlen(const char *str).

The EOF value itself is not a char, so shouldn't be stored as a char.

Hendeca
Posts: 3
Joined: Fri Apr 29, 2016 5:08 am

Re: Strange behavior of EOF in raspbian

Sat Apr 30, 2016 8:15 pm

Gotcha! Thank you all for your help! :D

alxprogramz
Posts: 8
Joined: Sat Apr 15, 2017 8:32 pm

Re: Strange behavior of EOF in raspbian

Tue Apr 18, 2017 9:17 pm

1
#include <stdio.h>
2
3 int main(void)
4 {
5 char ch = EOF;
6 printf("The value of ch is %d\n", ch);
7 printf("The value of EOF is %d\n", EOF);
8 return 0;
9
10 }
Output:
The value of ch is 255
The value of EOF is -1
[quote][/quote]
Thank you for helping out. Had to replace char data type to an int data type and the code works fine.

Return to “C/C++”