Stdout redirect output change

I have a program called abc .

When I run the following command:

 $ ./abc < infile 

I get the following output:

 ijklm 

However, when I run:

 $ ./abc < infile > outfile $ cat outfile 

I have been given this conclusion:

 ijkoo 

Now I assume that this is a bug with my program. However, no matter what my program does, I do not know how this is possible.

EDIT:

Now that I know that this is possible, I am curious what exactly causes this in my program.

My program has a block inside the loop that contains:

 byte = ascii_to_byte(asciibyte); putchar(byte); 

byte is of type char .

Now, if I change putchar(byte) to printf("%c", byte) , all output remains unchanged.

However, if I change it to printf("%d", byte) , then $ ./abc < infile displays:

 105106107111111 

Which is the decimal representation of these ascii characters, as they were in the outfile . But this is not a decimal representation of the characters, as they actually appeared when they were simply sent to stdout. I do not understand why this difference can be.

EDIT # 2:

If I change the print line to printf("%c\n", byte) , then $ ./abc < infile prints:

 i j k o o 

This is consistent with what goes into the outfile. Again, not sure what the difference is.

EDIT No. 3

I just tested this on a 32 bit machine and the program works: outputfile contains ijklm . Wierd.

EDIT # 4

Here is the main function:

 int main() { char asciibyte[8]; char byte; int c; //Using int to avoid the EOF pitfall. long charcount = 0; while((c = getchar()) != EOF){ if(c != '0' && c != '1'){ continue; } asciibyte[charcount % 8] = c; if(charcount % 8 == 7){ /*Testing revealed that at this point asciibyte does contain what it should contain, eight ASCII ones and zeros representing a byte read in from stdin*/ byte = ascii_to_byte(asciibyte); /*Print statements such as: printf("%d", byte); printf("%c\n", byte); reveal that the ascii_to_byte function works incorrectly on my 64 bit machine. However these statements: putchar(byte); printf("%c", byte); make it appear as though the function operates as it should. EXCEPT if i redirect that output to a file.*/ putchar(byte); } charcount++; } return 0; } 

And here is the ascii_to_byte function:

 char ascii_to_byte(char *asciibyte){ char byte; int i; for(i = 0; i < 8; ++i){ if(asciibyte[7-i] == '1'){ byte = byte | (1 << i); } } return byte; } 

FINAL IMAGE

I noticed that I had to initialize the byte to 0x00. The problem is solved. Why am I lagging behind? I will give answers to the question of who can explain specifically how this caused the problem.

+6
source share
4 answers

Such strange behavior that comes and goes in accordance with seemingly unrelated changes probably indicates that your program is reading or writing to memory, and this should not change, but a change in behavior, since other parts of the code use a different use of the stack and / or a bunch.

I would carefully check your code for errors such as buffer overflows, functions that return pointers to variables on the stack, etc.

Running code with a debugger can be productive (or it can change behavior again if you're out of luck!).

There are several interesting things you saw:

  • How can stdout redirection affect anything? Perhaps because this leads to the C library behaving differently: the stream uses a different buffering mode, depending on whether it is connected to a terminal device or not (see the GNU libc or C99 Documentation ยง7.9. 13, paragraph 7).

  • Why putchar(byte) n't changing putchar(byte) to printf("%c", byte) change anything when both printf("%d", byte) and printf("%c\n", byte) change their behavior? Perhaps due to the fact that the compiler automatically overwrites printf("%c", byte) into a more efficient putchar(byte) - usually the latest versions of GCC do this, even if optimization is not enabled, whereas printf("%d", byte) and printf("%c\n", byte) will actually compile as printf() calls.

+3
source

Of course, it is possible - the program could check whether it records the terminal and writes something different from what it will write when recording in the channel.

+1
source

As you say, byte uninitialized, so anything may arise.

One of the things that can happen is that byte "starts" at 0 and stores its value from calling the function to calling the function (as if it were declared static).

  in binary ...

    byte |  c (bin) |  byte |  c
 ----------- + -------------- + --------------
  00000000 |  i (01101001) |  01101001 (i)
  01101001 |  j (01101010) |  01101011 (k) * strange you get 'j', but anything can happen :)
  01101011 |  k (01101011) |  01101011 (k)
  01101011 |  l (01101100) |  01101111 (o)
  01101111 |  m (01101101) |  01101111 (o)
+1
source

What Neil Butterworth says. This function is called isatty .

 if (isatty(STDOUT)) printf("I am printing to the terminal!\n"); 

In addition, when testing the material, you could do:

 $ ./abc < infile > infile 

by chance. This way, you can quickly check that the infile really contains the same data.

0
source

Source: https://habr.com/ru/post/888911/


All Articles