Mysterious Memset
vector-of-bool.github.io
vector-of-bool.github.io
Very few other languages have a similar rule (eg. Rust explicitly does not have this rule)
That's not true, in C++ a byte is guaranteed to be able to hold a UTF-8 code unit.
https://timsong-cpp.github.io/cppwp/n4868/intro.memory#1.sen...
Alternatively, it implies that there's alot of broken code out there. So much broken code that they've accidentally found safety in numbers, and compilers are unlikely to change a coincidental behavior upon which they wrongly relied. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66110
One chink in this rule is interior mutability. This is why it is better to think of `&T` as a shared reference than an immutable reference. For example in the following code Rust can't assume that `a.get() == 5`. (Even if the second argument is changed to i8)
pub fn test(a: &std::cell::Cell<u8>, b: &std::cell::Cell<u8>) -> u8 {
a.set(5);
b.set(7);
a.get()
}
https://rust.godbolt.org/z/e1c6Kx4ebCommenting out the write to b does allow Rust to hardcode the return value as 5.
struct s {
int count;
char *chars;
};So, the "*count" in the example is a stand-in for a zillion other things you would actually have written, and that would also be affected by aliasing assumptions.
in the case of memset, it's questionable if that library call is actually faster for count < 128
https://en.cppreference.com/w/c/language/restrict
Still missing from C++ after all these years. Get it in there, people!
See also:
This is an aliasing issue, which is pretty well defined.
Am I missing something?
Other than that: Interesting insight!
> [...]
> Am I missing something?
`int*` and `char8_t*` aliasing is UB under strict aliasing.
You can call it "an aliasing issue, which is pretty well defined". As far as the compiler is concerned it's no different than every other UB it uses for constraints inference.
So the compiler can assume they didn't and is allowed to optimize away the loop with memset.
I know this is probably not all due to the language, but at least one bit of it has to be. It's really cool if you're writing bare-metal/RTOS level embedded stuff and you're worrying about how many assigments can you put into a loop round to optimize the cache lines, but I don't understand why anyone would ever try to talk to the web using C++.
This is a embedded thing, not a C or C++ thing.
The other day someone was saying here on HN that writing Verilog feels like following a process where "you already more or less know which circuit do you want, you are just trying to figure which is the specific Verilog code that will get your synthesizer to generate that circuit".
On embedded platforms (or generally anywhere where you count memory usage in units of KB or less), that's exactly what many people do. They already know more or less the assembly code, they are just looking for the right higher-level program that will translate to that assembly. That's one of the reasons they get angry when the language tries to be too smart.
The reason you just don't code in assembly directly is because it's still a pain and your chances of mistake increase (e.g. doing complex arithmetic expressions).
Had you not been "sure", you might have done something that would work right.
It still a Linux box, with plenty of memory to spare. This IS a C++ problem, where people are driven to do these insane optimizations.
I think a large part of it is due to the language. C++ code can be simultaneously both very low-level and highly-abstracted and then you will get reviewers complaining about needlesly copying 48 bytes while making a network request...
What else do you propose ?
> I know this is probably not all due to the language, but at least one bit of it has to be
No, there’s a cultural problem. C++ gives you the power and flexibility to really optimize for space or performance but rarely is that worth it early in development. Instead, just start by simply writing the code. Good design will give you affordances for appropriate optimization later.
And if your “embedded” system is so massive it can run Linux then you could end up with better code density by using Python source and including the interpreter!
The code snippets
for (int i = 0; i < *count; ++i) {
str[i] = 0;
}
and if (*count > 0) {
long idx = 0;
do {
str->__data[idx] = 0;
idx += 1;
} while (idx <= *count);
}
Will produce the same changes to the string data given the same count.