4 ms·
> When using fread, some implementations use the entire buffer as a temporary work space, even if the returns a length less than the entire buffer. So the follo
by eqvinox 4y ago
> When using fread, some implementations use the entire buffer as a temporary work space, even if the returns a length less than the entire buffer. So the following won’t work reliably:
char buf[N] = {0};
fread(buf, N-1, 1, f);
puts(buf);
This doesn't work reliably because the arguments are wrong. It's "fread(buf, size_of_item, number_of_items, file_ptr)". You're telling it to read one item of size N-1. If there's not enough data to read for a complete item, the rest of the "item" might be written with garbage. If you do it the right way around - reading N-1 items of size 1, you actually get the result you expect.
Is this an unnecessary footgun in the standard C library API? Probably yes. But if you complain about it, I really rather you complain about the actual problem.
Other than this, there's a few things I would agree with, and then a few other things that are issues with _specific_ standard C libraries, e.g. assert just exiting the process. Mixing C library API / POSIX problems with specific C library problems isn't particularly great for an article like this.
Anyway, the article registers appropriately "uncooked" for someone reinventing pkg-config; as far as my personal "reputation database" is concerned this is strike 2 for the author.
- jdefr89 4y agoI too am surprised. The author generally writes clean code, most of it seems to rely heavily on libC… I am confused…
- eqvinox 4y agoThe article is indeed rather fuzzy about what "libc" is. It seems to exclude "things provided by the compiler" while talking about varargs, but later calls out atomics with no such note.
- arka2147483647 4y agoThe subject is messy. For example; traditionally memset() and memcpy() are clib functions, but ofcourse nowdays any good compiler will intrisic or optimize those. Same for atomics.
- deleted 4y ago[deleted]
- spc476 4y agoIf you follow the links, most of the complaints stem from the Microsoft Windows implementation of the C Standard.
- matheusmoreira 4y agoHonestly I don't blame him. Perhaps he's used to read where the number of bytes to read follows the buffer: https://man7.org/linux/man-pages/man2/read.2.html https://man7.org/linux/man-pages/man2/read.2.html ssize_t read(int fd, void *buf, size_t count); That's how it works in every sane I/O API I've seen. What's even the point of the size_of_item argument?
- eqvinox 4y agoI agree it's a weird API. Not sure where it comes from, maybe some '70s thing with reading blocks? However, this functions as a red flag for the article itself, as in: in an article dismissing something with very little nuance, finding one of the arguments exhibit a lack of good understanding of that thing raises an interrupt for me that its other arguments may also be flawed. The article overall just rubs me as hubris. If you go about dismissing decades of engineering history, you better get your facts right. It's easy to write things like this when you're at the wrong end of the Dunning-Kruger bathtub, so you have to show you are in fact at the right end of it. (While in the middle, people tend to not write articles like this in my experience.)
- shanebellone 4y ago"wrong end of the Dunning-Kruger bathtub, so you have to show you are in fact at the right end of it." It seems so simple. Yet certainty eludes me. "Dunning-Kruger bathtub" This phrasing is gold btw.
- astrange 4y agoDoesn't exist though. (Not only did Dunning-Kruger not even claim that incompetent people believed they were confident, but the entire study doesn't reproduce.)
- shanebellone 4y agoI learned the term in grad school. Wikipedia seems fairly accurate. "Many criticisms of the Dunning–Kruger effect have the metacognitive account as their main focus but agree with the empirical findings themselves." https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect#Criticism_and_alternatives https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect#... Would it even matter? It's regularly used to describe a common phenomenon. You understood what the Parent Comment was describing, as did I. For that reason alone, it's effective communication.
- theteapot 4y ago> This doesn't work reliably because the arguments are wrong. It's "fread(buf, size_of_item, number_of_items, file_ptr)". No it isn't. What C standard library are you using? Above code is correct in my C standard library ... man fread: SYNOPSIS #include <stdio.h> size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); .... The function fread() reads nmemb items of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.
- eqvinox 4y agohttps://pubs.opengroup.org/onlinepubs/007904975/functions/fread.html https://pubs.opengroup.org/onlinepubs/007904975/functions/fr... "The fread() function shall read into the array pointed to by ptr up to nitems elements whose size is specified by size in bytes, from the stream pointed to by stream. For each object, size calls shall be made to the fgetc() function and the results stored, in the order read, in an array of unsigned char exactly overlaying the object. […] If a partial element is read, its value is unspecified." It doesn't say you stop when fgetc() returns EOF (or an error), so by a strict reading the remainder of partial items is filled with fgetc()'s "EOF" return value. But the more relevant thing is that it says the value of a partial element is unspecified. (Edited to point out the "unspecified" aspect.)
- ntrz 4y agoHow does the man page's "size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);" disagree with the GP's "fread(buf, size_of_item, number_of_items, file_ptr)"? Both seem to support that "fread(buf, N-1, 1, f);" is "telling it to read one item of size N-1".
- theteapot 4y agoOh it doesn't. Sorry. Too early not enough sleep to be commenting ...
- tom_ 4y agoAnother way of looking at it: if you don't want fread to overwrite N-1 bytes, don't tell it it can overwrite N-1 bytes! (Also, check the return value...)
- Karellen 4y agoI think the author does want fread() to overwrite N-1 bytes, iff there are N-1 bytes to read. The objection is to overwriting N-1 bytes when only N-2 bytes were read. Which... doesn't sound completely unreasonable? On the other hand (especially with SIMD CPUs, but maybe also with simpler instruction sets) I can understand that copying blocks of e.g. 8 bytes at a time might be faster than the special case at the end of a read for copying only 7 bytes. (Because you need to follow an "unlikely" branch to get to the 7-byte code which stalls the CPU, maybe.) So if the output buffer has space for it, it might be more performant to copy 8 bytes including a junk byte and just say you copied 7, than copying only 7 bytes. And the author does seem to object to a number of other design decisions which could hurt performance.