snaptoken / kilo-tutorial

build your own text editor
http://viewsourcecode.org/snaptoken/kilo
825 stars 80 forks source link

Why am I entering the while loop straight away in main() ? #36

Closed cassepipe closed 3 years ago

cassepipe commented 5 years ago

I have tried to add a printf() to main() in your code "parse-response" from github because it seemed to me that the while loop was executed right away and I also added a call to editorReadkey. The behavior is quite strange : The program does wait for a keypress but nothing is printed, then it gets into the rendering loop and and when I quit then printf is called ans prints to the terminal. I can't seem to get my head around this. Are while loops executed first by default in C ? I thought everything was linear.

int main() {
  enableRawMode();
  printf("Entering initEditor");
  editorReadKey();
  initEditor();

  while (1) {
    editorRefreshScreen();
    editorProcessKeypress();
  }

  return 0;
}
paigeruten commented 5 years ago

Interesting problem! Yes, everything should be running linearly.

I played around with it a bit and the problem seems to be that printf is doing line-buffered output. That means it only actually sends the text Entering initEditor when you print a line break, or when the program exits. editorRefreshScreen(), on the other hand, writes directly to stdout using write(), which doesn't do line-buffering I guess.

So you could fix by adding a line break (\r\n, since we're in raw mode):

printf("Entering initEditor\r\n");

Or you could flush the output after calling printf, to force it to send the output to the terminal:

printf("Entering initEditor");
fflush(stdout);
cassepipe commented 5 years ago

Thanks, it worked but I am not sure I understand why.

If printf() sends the text only when it can put a null character at the end of the buffer it returns, why does it normally work when I use it without a line break ? Where does the line break comes from then ?

paigeruten commented 5 years ago

Good question... I'm not an expert at this stuff but from doing some experiments I found a couple cases where it does work without the line break:

One is simply when the program exits:

#include <stdio.h>

int main() {
  printf("test");
  return 0;
}

Another is when you read some user input:

#include <stdio.h>

int main() {
  printf("test? ");
  getchar();
  return 0;
}

But if you don't do anything after the printf(), it won't print anything unless you have a line break:

#include <stdio.h>

int main() {
  printf("test");
  while (1) { /* infinite loop */ }
  return 0;
}

My guess is that getchar() and fgets() and any other functions that read user input, do the equivalent of fflush(stdout) before waiting for input. But in kilo, we're getting input at a very low level, in raw mode, so this won't happen in that case.

cassepipe commented 5 years ago

Thank you

I have learned from here that when there is no formatting involved the compiler replaces printf() with puts() : https://www.maizure.org/projects/printf/index.html

I am not sure I understand everything but this also helped a little : https://www.maizure.org/projects/printf/index.html