6 ms·
I've been writing a large app in C again after a few years away. Originally wrote the app in C++ then again in Python and now in straight C. I enjoy the faster
by linuxlizard 7y ago
I've been writing a large app in C again after a few years away. Originally wrote the app in C++ then again in Python and now in straight C. I enjoy the faster compile times of C (over C++) and the better type checking of C (over Python).
However, when I'm carefully using C++, I don't have to fiddle around with memory management and still get fast performance and better type checking.
Yesterday I wrote a Python script to generate C code test cases. String manipulation in Python is very easy.
The right tool for the right job, I suppose.
- swiley 7y agoI honestly don’t like C++ at all as a programmer, “C” is way better for hacking. For example: I understand why the standard was written the way it was but syntactic closures in C++ are way worse than GNU C.
- saagarjha 7y agoWhat are syntactic closures in GNU C?
- swiley 7y agoThis [1] explains how to create them using nested functions. Near the end is a quick blurb about the implementation which is probably why c++ doesn’t do it that way. [1] https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html
- saagarjha 7y agoOh no, nested functions are a terrible, insecure hack that are far too verbose to be ergonomic closures :(
- swiley 7y agoOf course, that’s why I said it’s good for hacking. Although I’m not sure I agree about the “ergonomic” thing.
- amiga_500 7y agoWouldn't you just use a lambda nowadays?
- im3w1l 7y agoNot in C you wouldn't.
- geofft 7y agoDon't GNU C's closures/nested functions require an executable stack or something? I remember GNU GRUB going through and getting rid of all of them.
- saagarjha 7y agoYes, because that’s where they put trampolines that are generated on the fly. (They don’t need to do this, but that’s how it’s currently implemented.)
- Gibbon1 7y agoI use them. The executable stack bit doesn't bother me since I'm on an ARM Cortex. Would be nice if they fixed that because they are kinda handy once you get used to them.
- geofft 7y ago> The executable stack bit doesn't bother me since I'm on an ARM Cortex. I'm not familiar enough with ARM - what does ARM Cortex give you here?
- Gibbon1 7y agoIt's what it doesn't give me. Doesn't have a memory management unit, so no stack execution protection. So no protection against classic stack smashing attacks. I saw a talk about weird machines. The upshot of it is if you can clobber the return address on the stack you can usually create a weird machine that you can then program[1]. Leads me to believe that if you are putting entrusted data and return addresses on the same stack you're in a state of sin security wise. https://en.wikipedia.org/wiki/Weird_machine https://en.wikipedia.org/wiki/Weird_machine [1] Also saw an exploit on an embedded system where they leveraged that even though the memory was locked you could set the program counter and read/write registers via jtag. Using that they were able in short order to recover the devices security keys and re-flash it with their own code.
- 7y ago
- JustSomeNobody 7y agoI don’t like C++ anymore. I used to love it but now it’s just a bloated mess of a language. I get it, you don’t have to use every part of the language but I really don’t like any of the newer bits and that’s what everyone wants to use.
- bbmario 7y agoHow do you generate the test cases? Check the types being fed in and fed out, then generate random input/output scenarios?
- linuxlizard 7y agoIt's pretty simple. I'm decoding a structure into bit fields (802.11 Information Element). I have a hex dump that I decode into a two structures with almost 100 fields (eyeroll for 802.11 committee). Each field can only be 0, 1, or sometimes up to 15. I have a list of the structure members. I generate an assert for each member being a certain value. The python script builds/runs the C code. On failure, I parse the assertion failure, get the actual value, change the C assert string, rebuild-rerun. Continue until the program succeeds. I've visually verified the decode is correct once. I want to keep the decoder tested if I change the code again so I'm generating complete test coverage.
- jupp0r 7y agoIt sounds like your use case is property based testing. Have you tried any of the QuickCheck ports to C++? My favorite is RapidCheck (https://github.com/emil-e/rapidcheck https://github.com/emil-e/rapidcheck). You define generators for your struct fields and write a pure function to check whether the parsed output conforms to your expectations.
- linuxlizard 7y agoChecking that out now! Reminds me a little of the Python library Hypothesis. https://hypothesis.readthedocs.io/en/latest/ https://hypothesis.readthedocs.io/en/latest/
- i80and 7y ago> better type checking of C (over Python). Note that Python's official type checker (mypy) is pretty good (within the limits of type erasure); I started the project I've been leading up at work this past year in statically-typed Python, and it's been a great experience.
- linuxlizard 7y agoI haven't tried mypy yet but want to get to it. It sounds very interesting! After using Python so much the last several years, I've gotten more curmudgeonly about strong type checking in my programming languages.
- takeda 7y agoDon't wait for a new project, just start using it (is most beneficial if for every function you specify types for parameters and output). If you use an IDE that understand it like PyCharm, suddenly the autocomplete will start working right, so will refactoring and it will start highlighting potential errors.
- codr7 7y agoI tried to like mypy, really did. But it always ended up in some kind of circular import tailspin for me. C++ gets around the problem by allowing separation of interface and implementation, Haskell by allowing circular imports. Maybe I missed something, maybe it's fixed by now, but that was my experience a couple of years ago.
- h8hawk 7y agoThey made a flag TYPE_CHECKING to avoid circular import in type checking. Its ugly but works. https://docs.python.org/3/library/typing.html#typing.TYPE_CHECKING https://docs.python.org/3/library/typing.html#typing.TYPE_CH...
- weberc2 7y agoAlso the circular imports was the least of the problems I’ve run into with mypy. They still can’t model a JSON type because it is recursive.
- umvi 7y ago> Yesterday I wrote a Python script to generate C code test cases. I do this quite a bit. Basically, anytime there is something very boiler-platy (like HTTP APIs, configuration management, test cases, etc.) I write metadata in JSON that describes what I'm adding, and then at build time a python script will parse the metadata and generate all of the C or C++ which is then compiled. I even have the python generating comments in the generated C/C++! I used to use Jinja2 for generating the C/C++ files, but now I just use f-strings in the latest version of vanilla Python3.
- cookrn 7y agoThis is really interesting — nice work! Have you published any tooling as OSS or examples? If you haven’t seen it before, the Model Oriented Programming work by Pieter Hintjens is worth looking at.
- umvi 7y agoNot yet. Most of the stuff I've done is internal to my company unfortunately. But just to give you an idea, if I were adding a new configuration parameter to our IoT device, I would add an object to a JSON array that looks like this: { "name": "backoff_mode", "group": "telemetry", "description": "We don't want to clog up networks with tons of failing attempts to send home telemetry. This parameter configures the device to back off attempts according to the specified mode", "cpptype": "std::string", "enum": ["none", "linear", "exponential"], "default_value": "exponential" } At build time, a few things are generated, including a .h file with the following: struct telemetry_config { ... std::string backoff_mode = "exponential"; //Possible values: ["none", "linear", "exponential"] }; The boilerplate for getting and setting this parameter is also generated. Thus, just by adding that simple piece of metadata, all the boilerplate and documentation is generated and you as the developer can focus on the actual logic that needs to be implemented regarding this parameter.
- thibran 7y agoThis is what Lisp/Scheme based languages use macros for -> to reduce boilerplate code. A lot of programmers hate DSL's, but using Python to generate test code is the same as using a DSL. The difference is, Python is a much bigger and more complicated DSL, than a test-macro will probably ever be. There is nothing wrong with generating code in a pragmatic way. It is just strange to see all the time people using workarounds for things that a tiny DSL could probably solve better.
- 1996 7y agoFunny I do that in perl, and some people freak out about having code in an unfashionable language generating code in another language. It's just equivalent to a preprocessor.
- lizmat 7y agoIn the mid-90's, before mod_perl, I used to generate PHP in minutely cron job using a Perl script from a constantly changing database. That came close to the best of both worlds at the time: the flexibility of Perl, fed from a database, and no CGI overhead when serving.
- marcosdumay 7y agoCode generation usually sucks. A small one-off run under your control is an exception. But people learn to fear the thing, and apply that fear everywhere.
- vageli 7y ago> Code generation usually sucks. > A small one-off run under your control is an exception. But people learn to fear the thing, and apply that fear everywhere. Why does it usually suck? Writing code that writes code seems like an optimization that would bolster productivity.
- karatinversion 7y agoMost of the code generation code I’ve seen is itself opaque and generates opaque code. This makes refactoring, extending and bug fixing hard.
- marcosdumay 7y ago> Why does it usually suck? One large factor is that when somebody really dislike the result of a code generator, they most commonly cope by editing the generated code by hand. With other metaprogramming techniques people can't do the same, so they fix the issues. The end result is that code generators are usually a set of mostly-functioning tools that create bad code that is almost, but not exactly impossible to understand but that you will be required to change at some point.
- app4soft 7y agoHere is AzPainter — obscure image editor for painters with PSD-format support & modern UI, written in pure C with own GUI toolkit on top of X11.[0] Few years ago it fully rewritten from C++ to C. [0] https://github.com/Symbian9/azpainter https://github.com/Symbian9/azpainter
- squarefoot 7y agoThanks for the link! I just installed it on my i5 Thinkpad. I can't test filters and more complex stuff right now, but it loads super fast, like 150 ms uncached, and probably less than 50 ms when cached. I'm curious if there is other software around rewritten in pure C. It would likely be a huge task not worth the effort, but I can't but imagine the speed and size gains by rewriting say Firefox or Libreoffice.
- app4soft 7y ago> I'm curious if there is other software around rewritten in pure C. Can't answer for now, but check next awesome lists: • AWESOME C — https://github.com/Bfgeshka/awesome-c https://github.com/Bfgeshka/awesome-c • AWESOME C — https://github.com/kozross/awesome-c https://github.com/kozross/awesome-c | mirror — https://notabug.org/koz.ross/awesome-c https://notabug.org/koz.ross/awesome-c • AWESOME C — https://github.com/aleksandar-todorovic/awesome-c https://github.com/aleksandar-todorovic/awesome-c ∗ AWESOME C++ — https://github.com/fffaraz/awesome-cpp https://github.com/fffaraz/awesome-cpp
- aninteger 7y agoI think what squarefoot is looking for is lightweight (tiny?) C apps that have limited abstraction layers. For example, Gtk+, which is pure C, is no longer considered lightweight. It was with Gtk+ 1.2 because GTK was just a small wrapper around X11 in the 1.x days. That is what AzPainter is. AzPainter basically depends on xlib, xft/freetype, and some image libraries (libpng, libjpeg). Modern C apps with a GUI typically build on GTK but that toolkit has become massive. Modern GTK3 apps are built on top of dbus, pango, atk, cairo. This is not necessarily a bad thing though and libraries like ATK provide accessibility which is important. At the time GTK+ was created the competing toolkit at the time, under Unix, was Motif and it had the nickname "bloatif". Now we've reached a point where GTK3 is much much larger and "bloated" than a 2019 Motif application. If we include C++ the Qt and WxWidgets toolkits are also massive. FLTK is still a lightweight option though.
- kjhrklewiou 7y agoI enjoy using C++ from Python through Cython. This way you can have the speed and memory tightness of C++ where it matters, but do the other stuff, like initial data parsing and munging or overall control and sequencing in Python, thus avoiding the general clumsiness and unproductivity of C++
- fulafel 7y agoC has static typing but Python has strong (safe) typing. Many people would contest the claim that C is better here.
- hota_mazi 7y agoStrong typing is of little practical help when you're trying to read a code base with zero type annotations. Static typing is a superior approach that makes maintainability and refactoring orders of magnitude easier.
- fulafel 7y ago>100x advantage in those areas does sound pretty attractive! Maybe my memories of using C are faded. If you have references, I'd be interested.
- etatoby 7y agoHave you considered Nim? Much better type system than C, syntax is very similar to Python, compile times are excellent and speed analogous to C++.
- 01100011 7y agoIME, 'C with classes', or C++ but skipping the more esoteric features(OOP overuse, template metaprogramming) yields a fairly easy to understand language for most C folks. I'm a C guy and am most comfortable with it, but I like having the advanced data structures out of the box. Granted, most C codebases of any reasonable complexity have their own support for relevant data structures, but they're a lot cleaner to use via the STL. Python is a great tool for a certain class of jobs. I saw a company doing systems programming in Python and originally thought it was a great idea, and then I learned of the hidden(or not) dangers of Python. Yes, you definitely need to pick the right tool.