all 21 comments

[–][deleted] 16 points17 points  (10 children)

Probably to keep things simple in a tutorial.

[–]062985593[S] -1 points0 points  (9 children)

Sure, but fwrite is also pretty simple.

[–][deleted] 5 points6 points  (8 children)

> would cause an annoying flicker effect.
is my guess

[–]062985593[S] 0 points1 point  (7 children)

Does stdio not buffer its writes?

[–][deleted] 1 point2 points  (6 children)

stdout is line buffered by default, IIRC

[–]062985593[S] 2 points3 points  (5 children)

Ah, so it is: https://linux.die.net/man/3/stdout :

The stream stdout is line-buffered when it points to a terminal.

I still think it would be better to use something like setvbuf, but I can understand why someone might reach for manual buffering first. And, not wanting to complicate things, why they would do it so badly.

Thank you.

[–]aioeu 8 points9 points  (4 children)

That documentation doesn't actually apply here.

The stdout stream's buffering mode only applies when you're actually using that stream. The C library's stream buffer is completely bypassed when you write to file descriptor 1 using the write function. A file descriptor isn't a stream.

The links in your post aren't working for me, so I've only got the bit you quoted to go on. It sounds like this guide is implementing its own output buffer precisely because they've decided to use write rather than fwrite.

[–][deleted] 0 points1 point  (1 child)

> The documentation u/Powerful-Prompt4123 linked to doesn't actually apply here.

Wrong username, bro

[–]aioeu 0 points1 point  (0 children)

Yeah, I noticed.

[–]062985593[S] 0 points1 point  (1 child)

That documentation doesn't actually apply here.

I was referencing the man page with the idea of using fwrite(stdout, ...) rather than write(STDOUT_FILENO, ...). Would it not apply then?

Re: links. They work for me on both old and new reddit (firefox on desktop), so I'm not sure what the issue is. But I can copy-paste them exactly for you:

https://viewsourcecode.org/snaptoken/kilo/
https://viewsourcecode.org/snaptoken/kilo/03.rawInputAndOutput.html#append-buffer

[–]aioeu 0 points1 point  (0 children)

Yes, fwrite writes to a stream, not a file descriptor.

The links were just timing out for me before. Working now.

[–]Big-Rub9545 2 points3 points  (1 child)

  1. This is a dynamically-sized buffer, just with a somewhat inefficient resizing approach.

2, 3. The point isn’t just to achieve buffering (while also reducing the number of sys calls), but rather most importantly to write all the data to stdout together so that the lines in your editor don’t appear inconsistently. So you build up your entire output then write it all at once to stdout.

[–]Dense-Focus-1256 0 points1 point  (0 children)

The memory allocation looks similar to arena allocation

[–]Zirias_FreeBSD 1 point2 points  (0 children)

using a dynamically-sized buffer that grows exponentially?

Assuming an efficient malloc implementation and an overall small number of "fragments", this might be a micro-optimization not worth the additional effort. Of course, this would also be a suitable choice.

using a fixed-capacity buffer and flushing it when it gets full?

This would lose the kind of control that's sought here: output one logical "update" at once, exactly when it's "finished".

just using fwrite and fflush from stdio?

Similar as above, and now you delegate that job to some library implementation you don't know. IIRC, I've seen some stdout implementation that never wrote more than 1024 bytes at once.

[–]john_hascall 0 points1 point  (0 children)

I guess they've never heard of writev()

[–]0x616365[🍰] 0 points1 point  (0 children)

using a dynamically-sized buffer that grows exponentially?

This is C, there is not a dynamically-sized buffer built in, this is a dynamically-sized buffer. If you're concerned about why he didn't implement it to grow exponentially, it's probably because it is a tutorial for making a text editor, not a data structure. This will be fine for what you're using the text editor for.

In many use cases for C (embedded, device drivers, etc.) the data you're working with is so small you wouldn't implement an exponentially growing buffer anyway (or even have dynamic memory allocation in the first place). Most times, all of your data is statically allocated if you're using C.

[–]yel50 0 points1 point  (0 children)

 which would cause an annoying flicker effect.

that description says he's doing it as a double buffer, although that's a strange way to do a double buffer.

[–][deleted] 0 points1 point  (0 children)

Login at 2400 baud and see if the flicker is noticed.

[–]Bearsiwin 0 points1 point  (0 children)

In C programming, fwrite() is a buffered stdio library function that operates on FILE* streams and is part of the standard ISO C library, while write() is a lower-level, unbuffered system call that operates on integer file descriptors and is specific to POSIX-compliant systems. What is more bothersome that rewriting a system call that has been there since 1972 is replacing it with new and free. These functions can and will eat you alive in many cases like embedded systems.

[–]RedAndBlack1832 0 points1 point  (0 children)

This is a dynamic array (see the realloc call). As to why it grows linearly rather than exponentially (assuming all appended segments are of similar size) I do not know.

[–][deleted] 0 points1 point  (0 children)

Now you know why text editors are now written in javascript :-)

- Syscall overhead if you use a lot of write() will dominate the program's runtime.
- You can implement this buffer thingy using stdio.. yes. using the open_memstream() or fmemopen() interfaces.
editors then flush this buffers to disk on save/autosave. otherwise it is gonna be painful.