News for hackers. Stuff that matters.
Re:How to make smaller C and C++ binaries by Night_Thastus on Sunday May 07, 2023 @02:59PM (#35854463)
There's also some really terrible advice in here. Not using the STL is really, really bad advice for most. Same with fast-math. Same with "just write C instead lol".

If you're in an situation where binary size is absolutely critical, then sure. But most people should avoid most of these suggestions.

Re:How to make smaller C and C++ binaries by kevin_thibedeau on Sunday May 07, 2023 @03:39PM (#35854866)
He also recommends disabling exceptions which is a valid approach for size constrained applications. STL throws, so it can never be used safely with exceptions disabled. When you do this you're committing to writing C-with-classes rather than modern C++.
Re:How to make smaller C and C++ binaries by galangalalgol on Sunday May 07, 2023 @04:41PM (#35855434)
There have been implementations of most of the stl without exceptions here and there for embedded stuff. You can do modernish c++ without rtti or the stl, you will just have to do some extra work.
Re:How to make smaller C and C++ binaries by flafla2 on Sunday May 07, 2023 @05:24PM (#35855745)
I agree with the sentiment but in practice I’ve found that most C++ STL exceptions throw in a “fatal error” type of scenario like a bad allocation and generally not an “expected error”. For example, basic_ifstream::open() sets a fail bit on error, and doesn’t throw an exception.

This is in contrast to python or Swift for example, their standard libraries are more “throw-prone”. Building off the previous example Swift’s String.init(contentsOf:encoding:) throws on error on failure.

So in practice, IMO it is usually safe to disable exceptions in C++. Though, I have run into tricky ABI breaks when you link multiple libraries in a chain of exceptions->noexcept->exceptions and so on! You’re of course at the mercy of nonstandard behavior so buyer-beware. I definitely wouldn’t advocate for turning them off -just- for a binary size reduction.

Re:How to make smaller C and C++ binaries by kevin_thibedeau on Sunday May 07, 2023 @07:24PM (#35856559)
You can recover from failed allocations without catastrophic failure. It is a fundamentally lazy programming practice to pretend that error handling has to be an out of band operation that can't be dealt with locally and bubble up progressively.
Re:How to make smaller C and C++ binaries by Chaosvex on Sunday May 07, 2023 @09:30PM (#35857180)
You can try but realistically, you shouldn't bother in the overwhelming majority of software. Depending on whether you're on a platform that allows for overcommit, you won't necessarily know that an allocation has failed until you attempt to make use of it and the OS tries to back the pages, by which point, you could be far from the source of the allocation.

You're just going to end up with an insane amount of error handling only to discover that in the real world, there's likely nothing you can really do anyway.

Re:How to make smaller C and C++ binaries by DustinGadal on Monday May 08, 2023 @06:58AM (#35860211)
On platforms that allow overcommitment, you can guarantee your commit charge is physically backed by writing to each page in a memory pool at allocation time (probably at application startup, or at the end of the main loop), then allocating out of that pool.

Using memory that's been allocated but not committed seems like a recipe for disaster.

Re:How to make smaller C and C++ binaries by cma on Monday May 08, 2023 @12:48PM (#35863862)
> Using memory that's been allocated but not committed seems like a recipe for disaster.

It can greatly accelerate sparse datastructures.

Re:How to make smaller C and C++ binaries by vodou on Sunday May 07, 2023 @05:48PM (#35855937)
This is pretty uncontroversial in an embedded system context. As others have said in this thread, nothing spectacular happens if STL throws, it just boils down to a std::terminate. You can mitigate this by being careful with what you do with STL.

Also, in a real-time system context, exceptions can be undesirable since they might cause non-deterministic behaviour.

Catching an exception can be surprisingly costly. Did some benchmarking a while ago on the embedded, real-time system I work on and saw that throwing and catching a std::runtime_error had about the same execution time as a rather slow CRC32 calculation (no pre-calculated tables, no special instructions) of a 256 bytes input array. (Of course, this depends a lot of the CPU architecture, compiler, etc.)

Re:How to make smaller C and C++ binaries by Espressosaurus on Sunday May 07, 2023 @08:04PM (#35856781)
I haven't read the article yet, but it's standard operating procedure for embedded.

* No exceptions, ever

* No RTTI, ever

* Compile with -Os

* Limit STL to the non-allocating, non-throwing parts

* Don't allow heap usage

* Link against the C standard library so you don't get accidental heap allocations from lambdas with large capture specs and static construction and destruction fail to link

* Use alternatives to std::function (which while easy is very large and very slow)

* Limit the use of virtual functions (some people suggest eliminating them altogether but I feel like that's a bridge too far).

* Avoid inlining functions if you're not sure that they reduce down to something trivial. I've saved a kilobyte or two by moving some particularly large, commonly used functions into separate translation units so that the compiler couldn't inline them.

* Look at and track your space utilization commit by commit. If the data segment goes up unexpectedly, revisit what you're doing. You may have unwittingly allocated a big block for something. Similar for the code segment.

You get used to the constraints. Type safety, templates, and compile time programming make it 10 times better than C for the purpose in my experience. The only reason to use C is if your C++ compiler is garbage (which is often true for the tiny low powered processors). But if it's ARM you probably have access to a modern compiler and the only reason to stick with C is inertia.

I've been programming with embedded C++ for ten years and every time I have to poke into the C part of the codebase I end up hating life.

Re:How to make smaller C and C++ binaries by spacechild1 on Sunday May 07, 2023 @08:28PM (#35856872)
> so you don't get accidental heap allocations from lambdas with large capture specs

Lambdas themselves never require heap allocation. I guess you meant std::function?

Re:How to make smaller C and C++ binaries by Espressosaurus on Sunday May 07, 2023 @10:00PM (#35857305)
It depends on what you're using for your function type erasure, but yes.
Re:How to make smaller C and C++ binaries by flohofwoe on Monday May 08, 2023 @03:11AM (#35858934)
> STL throws, so it can never be used safely with exceptions disabled.

With exceptions disabled you still get a panic (e.g. the program immediately terminates) in places where an exception is thrown, this should be at least as safe as having exceptions enabled.

Re:How to make smaller C and C++ binaries by coliveira on Sunday May 07, 2023 @03:23PM (#35854710)
The stated goal of the article is to reduce binary size. If you want to use C++ and STL you already have decided that binary size is secondary. By the way, the article even mention rewrite some routines in assembly.
Re:How to make smaller C and C++ binaries by lozenge on Sunday May 07, 2023 @04:00PM (#35855069)
This is like saying "how to reduce the load time of your web app - remove all CSS". Technically true, but not useful for most web apps. People can want faster loading without removing all styling.
Re:How to make smaller C and C++ binaries by Kranar on Sunday May 07, 2023 @04:38PM (#35855416)
I don't see how your claim follows or would be true. Replacing CSS with the equivalent JavaScript would most certainly not reduce load times. You should use CSS precisely as a means of reducing load times.
Re:How to make smaller C and C++ binaries by wtetzner on Sunday May 07, 2023 @05:27PM (#35855770)
They didn't suggest replacing it with JavaScript.
Re:How to make smaller C and C++ binaries by Kranar on Sunday May 07, 2023 @05:57PM (#35856000)
They didn't really suggest anything. Feel free to propose a way of replacing CSS functionality that results in faster load times.
Re:How to make smaller C and C++ binaries by dgfitz on Sunday May 07, 2023 @09:59PM (#35857298)
I'd say the obvious answer in this case would be: replace it with nothing. The web would be a touch uglier, but it sure would be faster.
Re:How to make smaller C and C++ binaries by Kranar on Sunday May 07, 2023 @10:06PM (#35857341)
That's a different discussion and frankly not something for developers to decide. If a product is designed to behave and look a certain way, then as an engineer you have the job of determining the best way to accomplish that objective. If your decision is to forgo using CSS for an alternative, fine but no one has provided what that alternative is.

I'd much rather use CSS instead of Javascript or going back to the days of hacking <table> to get a certain layout.

Re:How to make smaller C and C++ binaries by ipaddr on Sunday May 07, 2023 @04:15PM (#35855219)
It's more like saying remove react and use pure javascript.
Re:How to make smaller C and C++ binaries by colonwqbang on Sunday May 07, 2023 @05:54PM (#35855976)
I think that's quite unfair. The article contains many different tips on how to reduce size. Rewriting in a different language was just one of them, pretty far down on the list.

"Write in C instead of C++" is also clearly not the same as "remove all your code"...

Re:How to make smaller C and C++ binaries by IChooseY0u on Sunday May 07, 2023 @03:46PM (#35854937)
Why is avoiding STL bad advice? Lack of problem solving skills? You could survive with LIST_ENTRY and UNICODE_STRING-type structures.
Re:How to make smaller C and C++ binaries by Kranar on Sunday May 07, 2023 @03:51PM (#35854989)
Not using the STL in and of itself is not terrible advice, it's a trade-off. For example, I tend to avoid the STL because of how inconsistent it is across the various compilers in terms of performance and behavior. The standard leaves a great deal of ambiguity in how the STL behaves and those inconsistencies can be frustrating to deal with when you're writing cross platform software. Furthermore plenty of embedded systems also cut out the STL entirely due to disabling exceptions. Using fast-math is also a perfectly acceptable option for numerous domains that do not need strict IEEE conformance, such as graphics programming or training neural networks.

If people were to listen to your advice, no one would ever post any kind of article on how to achieve certain specific goals, all we'd ever discuss are very generic topics and constantly rehash the same content over and over again. It's good to be able to learn how certain developers manage to accomplish various goals without having someone come along and call that advice terrible.

Re:How to make smaller C and C++ binaries by maccard on Sunday May 07, 2023 @05:21PM (#35855726)
> For example, I tend to avoid the STL because of how inconsistent it is across the various compilers in terms of performance and behavior.

What are your targets? This was my experience 10 years ago, but today with modern (last 5-6 years) MSVC, GCC and Clang (and even on modern Xbox and Playstation toolchains) my experience has been that it's close enough.

Re:How to make smaller C and C++ binaries by kwant_kiddo on Sunday May 07, 2023 @06:01PM (#35856037)
Even just between x86 and ARM there can be a big enough difference in performance s.t your product straight up does not work on one platform, and that is with the current gcc toolchain.

I have been working with small embedded devices so this may be an outlier here compared to the rest of the C/C++ world.

Re:How to make smaller C and C++ binaries by maccard on Monday May 08, 2023 @05:51AM (#35859827)
We target both x64 and arm, and I'm not aware of any restrictions we place on STL usage. That said, we don't target embedded devices, so your world is _definitely_ different to mine!
Re:How to make smaller C and C++ binaries by mkoubaa on Sunday May 07, 2023 @04:05PM (#35855117)
The title of the article is literally "How to make smaller C and C++ binaries"
Re:How to make smaller C and C++ binaries by bee_rider on Sunday May 07, 2023 @04:24PM (#35855295)
The advice for fast math is kinda funny.

> If you don't need IEEE-conformat floating point calculations, use -ffast-math .

I mean… if you know enough to know whether you need standard floating-point calculations, you probably know about the -ffast-math flag.

Someone who is more into system specific stuff might correct me, but I believe fast math produces a binary which can flip bits in the MXCSR if it wants. So, you’ll have to make sure that none of your libraries make any assumptions about floating point behavior, not just your code…

Re:How to make smaller C and C++ binaries by mananaysiempre on Sunday May 07, 2023 @06:59PM (#35856408)
> if you know enough to know whether you need standard floating-point calculations, you probably know about the -ffast-math flag.

If you just want physics engine go brr and a small binary, though, maybe you don’t.

I find the FP advice suspect for a different reason: I’ve seen some no good, very bad, seriously terrible, really horrifyingly awful codegen from Clang for x86-64 things involving `long double`, and without checking first I wouldn’t assume that it doesn’t extend to all x87 stuff in general.

(Clang’s preferred optimized way to copy a naturally-aligned 16-byte union with a `long double` being the longest member is... to copy the first ten bytes with FLD/FSTP, then the following two bytes of padding by a word-sized MOV, then the final four bytes, also of padding, by a doubleword-sized MOV. Apparently it forgot its MOVAPS at home.

When it spills onto the stack a `long double` temporary it itself invented to implement an atomic operation’s inner loop, though, it first clears the padding using a bleeding XORPS+MOVAPS pair before FSTPing it there—inside the loop, twice, to two identical temporaries, because apparently it belongs to the offshore oil rig school of register spilling.

And so on. I lack the words to describe how bad Clang’s codegen is for anything that might have ever briefly brushed against a `long double`.)

Also take care with -Os; while clang’s -Os is generally sane, gcc -Os will e.g. implement division by a constant with IDIV instead of magic multiplication, giving you code that’s maybe three times shorter and easily a dozen or two dozen times slower. (I think I remember Torvalds saying years ago that he gave up on gcc -Os.)

Re:How to make smaller C and C++ binaries by josephg on Sunday May 07, 2023 @11:15PM (#35857684)
> (Clang’s preferred optimized way to copy a naturally-aligned 16-byte union with a `long double` being the longest member is... to copy the first ten bytes with FLD/FSTP, then the following two bytes of padding by a word-sized MOV, then the final four bytes, also of padding, by a doubleword-sized MOV. Apparently it forgot its MOVAPS at home.

Is that still true? Might warrant a bug filed on clang/llvm.

Re:How to make smaller C and C++ binaries by mananaysiempre on Tuesday May 09, 2023 @07:59PM (#35881933)
On second glance, surprisingly (or maybe not), this is not as easy to trigger as I thought. The somewhat messy interpreter loop I’m using still exhibits the problem on Clang 14 today (and I mean, I wrote a workaround for that a month ago, how much could it have changed in the meantime). Yet if I just write out the same union (every scalar type in C, basically) and make a function that assigns some things of that union type to some other things, I can’t get the bad codegen to manifest even on Clang 9.

So I’d need to do some work to make a small reproducer; then I’d have to figure out how to get access to their bug tracker, because apparently letting people register their own accounts is too easy, let alone just send mail to an address. I don’t know if I have that in me.

(On a more positive note, do you know that sometimes, if you add `default: __builtin_unreachable();` to your switch-threaded interpreter loop, Clang will look at it and replicate the dispatch at the end of each bytecode instruction, like in the standard technique for better branch prediction in handwritten assembly-language interpreters? When I noticed that I couldn’t stop imagining it going “It looks you’re writing an interpreter. Would you like some help?”.)

Re:How to make smaller C and C++ binaries by cozzyd on Sunday May 07, 2023 @07:34PM (#35856620)
If I'm optimizing for binary size, I'm likely targeting a microcontroller that has no floating point unit, in which case the obvious size optimization is don't use floating point...
Re:How to make smaller C and C++ binaries by bee_rider on Sunday May 07, 2023 @07:41PM (#35856660)
What does the —ffast-math flag get you there?
Re:How to make smaller C and C++ binaries by cozzyd on Monday May 08, 2023 @12:47AM (#35858203)
nothing... you wouldn't use floating point math in the first place :)
Re:How to make smaller C and C++ binaries by stephc_int13 on Sunday May 07, 2023 @04:43PM (#35855450)
Are you aware that STL, exceptions and RTTI are verboten by most game studios?

Templates and operators overloading are also quite often frowned up.

https://gist.github.com/raizr/c08922b11b33477a1157156e424342...

Re:How to make smaller C and C++ binaries by lifthrasiir on Sunday May 07, 2023 @10:42PM (#35857527)
Are you aware that "most" game studios nowadays do not use C++ as a primary language anyway? AAA games are really a small portion of all gamedevs anyway, and the stance against modern C++ is not universal even in the gamedev community. Even the linked article states that C++17 is probably fine now, and that's cleanly modern.
Re:How to make smaller C and C++ binaries by mastax on Sunday May 07, 2023 @07:18PM (#35856519)
It's a list of things you can choose to do, and it discusses the trade-offs in most cases.

It would be terrible advice if it were framed as "do all these things."

Re:How to make smaller C and C++ binaries by crest on Sunday May 07, 2023 @07:37PM (#35856632)
So is using binary packers like UPX. Not just will they sound the alarm in a lot of so called security products, but they'll also prevent the operating system from sharing the RAM used to mmap() read-only and read-execute pages from the executable while increasing startup times. Removing random sections will also cause headaches when it comes to tracing and debugging in production. Just accept that those sections fulfil real world requirements and aren't just shiny nerd knobs for knobs to mess with. If your code isn't worth being traceable/debuggable in production it's not worth having it installed on production servers.

Also don't go too far with the build flags or you risk waking the sleeping horrors lurking in the seldom tested dark corners of the compilers and linkers we all rely on e.g. accidentally changing the effective ABI through tricks like smaller enums. Some of those bugs may only trigger on certain architectures e.g. exception handling works differently on amd64 and aarch64. On one of the two uses special an extra section to locate the unwind helpers. Do you know the all implications of removing a section from an executable? sigh

Please keep bloat down, but eager developers shouldn't too far beyond the point of quickly diminishing returns within a given ecosystem they're targeting.

Re:How to make smaller C and C++ binaries by NL807 on Sunday May 07, 2023 @10:45PM (#35857551)
Some of the advice listed on here is quite outdated by today's standards.
Re:How to make smaller C and C++ binaries by flohofwoe on Monday May 08, 2023 @03:07AM (#35858904)
> Not using the STL is really, really bad advice for most.

Not really, the STL is an accumulation of mediocre design decisions (mostly because it needs to be "everything to everybody"), which can't be fixed because of backward compatibility requirements. In many situations it's actually better to write your own specialized helper classes.

Re:How to make smaller C and C++ binaries by maldev on Monday May 08, 2023 @07:08AM (#35860276)
I don't think many actually use the STL besides app dev's. Most systems dev's are targeting WIN32, RTL, UEFI, POSIX, BOOST, UNREAL, or something else. Not only this, but STL also breaks alot of things by what it puts in, Kernel, Unreal, and results in alot of usecases to not use the STL.

The only time in my entire career i've ever used the STL was in college. Since most C++ jobs are not Appdevs. All those have moved to C#, Go, or some other higher level language. Or again, just rely on the built in suite like RTL, Posix, Unreal