简体   繁体   中英

Two distinct characters sharing same ASCII value in C

I am using Linux x86_64 with gcc 4.8.1.

Code:

#include <stdio.h>

int main(int argc, char *argv[])
{
    int ch;

    do
    {
        printf("ch : ");
        ch = getchar();         //Q Why CTRL+M = 10 and not 13?
        getchar();
        printf("ch = %d\n\n", ch);
    }while(ch != 'z');

    return 0;
}

Output:

ch : ^N
ch = 14

ch :   

ch = 10  

ch :   

ch = 10  

ch : z  
ch = 122  

Question:
In above program when I enter Ctrl+J (linefeed character) it spits 10 which is indeed the ASCII of \\n But when I feed Ctrl+M (carriage-return character) then too it spits 10 instead of 13 (ASCII value of \\r ).

What's going on? Does \\n and \\r share the same ASCII value? Then which character represents ASCII 13?

EDIT:

$ uname -a  
Linux Titanic 3.11.0-26-generic #45-Ubuntu SMP Tue Jul 15 04:02:06 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

The problem is that ICRNL is enabled in the terminal driver. Here's a snippet from the man page for tcsetattr(3) , which is used from C to set terminal attributes:

ICRNL Translate carriage return to newline on input (unless IGNCR is set).

To disable ICRNL , you can run the following command before your program (or use tcsetattr() directly):

$ stty -icrnl

stty -a lets you view the current terminal settings.

Note that the above will prevent your Enter key from working normally too (since it generates a carriage return, while the terminal driver is waiting for a linefeed to terminate the line before sending it to your program). You will have to use Ctrl-J instead. :)

Below is a tangent on why Return still works in the shell with IGNCR disabled (in Bash at least), in case you're interested:

Bash uses the readline library to read commands. Before reading a command, readline puts the terminal into noncanonical mode, where input is unbuffered (can be read a character at a time, as soon as a character is typed). readline therefore sees the carriage return character as soon as it is typed, and happens to accept it as a line terminator.

Noncanonical mode is needed to implement fancy line editing like being able to move the cursor with the cursor keys and insert text in the middle of a command. Text UI libraries like ncurses also use this mode.

While your C program runs, the terminal is in canonical mode instead, where the terminal driver does line buffering (sends the input to the process a line at a time). This mode only has rudimentary line editing (eg, erasing is supported) and does not interpret the cursor keys, which is why you get strange characters sequences on the screen when you press them. (Those characters are the terminal escape sequences generated by the cursor keys, which become visible in this mode. A handy command to experiment with is a plain cat with no arguments.)

Canonical mode is enabled/disabled through ICANON , which is an option just like IGNCR . Experimenting with it from the shell might be a bit tricky though, since the shell sets and resets it as programs (like stty ) are run.

I don't know the ^J keyboard shortcut, but I'm willing to bet that if you feed your code with a fixed character (not read from terminal) '\\r' and '\\n' you'll get the proper ASCII values. This means it is either your terminal setup that's wrong like @alk said, or ^J doesn't do what you think it does...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM