Live data from Hacker News

Using Zig to Unit Test a C Application

mtlynch.io

31–40 of 54 posts

Re: Using Zig to Unit Test a C Application

#31

Curious now if you could use D in the same way? Walter Bright built a faster preprocessor for Facebook (kind of a sidenote and not fully relevant), wouldnt surprise me if D is another good candidate especially given its age.

Yes: https://dlang.org/spec/importc.html

The D compiler(s), as Zig, can be used to compile C code... and D code can import C files as if they were D modules (as in Zig, there are some special types to represent C strings and other types that are not exactly the same).

Re: Using Zig to Unit Test a C Application

#32

I also now always use Zig to write tests and benchmarks for C code. This is for example the case in libaegis: https://github.com/jedisct1/libaegis Calling C functions from Zig is easy (C headers can be imported directly) and doesn't have any overhead. So I can take advantage of the convenience of Zig, even if the tested code only requires a C compiler. I also now always add Zig build files as an alternative to make/l…

> The main advantage is that cross-compilation to many targets is supported out of the box

For the readers who aren't familiar:

The code for running test and then cross-compiling (on one machine and OS) for different target platforms is:

https://github.com/jedisct1/libaegis/blob/main/.github/workf...

and the only zig file in the repo which drives the build process is:

https://github.com/jedisct1/libaegis/blob/main/build.zig

Re: Using Zig to Unit Test a C Application

#33

This is going to get really good when zlibc is done, you'll be able to for example, override the c stdlib "free" function in the c code and add features, for example (runtime) UAF/DF detection with metadata tracking (like stacktraces of where the memory was created and freed)

You can do that in any C program today

Re: Using Zig to Unit Test a C Application

#34
post #4

zig , ocaml, odin many system languages are making the headlines lately its very hard to pick one to learn not sure how to deal with this, learn them all, bet on one, what should we do

I was in the exact same situation. I know Rust but don't want to use it for everything... had a look at:

Zig - attempts to stay simple, like C, but with warts fixed and with cool compile-time programming. Its biggest strength seems to be not the language itself, but the compiler and build system which can cross-compile seamlessly, including C code.

Nim - a systems-language that looks like Python and tries to be fun to write. Has macros that may remind you of Lisp macros. Compiles to C or JS.

D - older but very cool as well... I was surprised to find out its metaprogramming capabilities are as good as Zig's or Nim, and that is has a lot of cool features not seen in mainstream languages, like contract programming and executable documentation. Much more mature than the previous ones. Also seamlessly compiles and imports C.

Odin - really reminds me of Go. It's used in production to create fluid simulation for Holywood movies apparently. Very minimalistic language but I couldn't see what it brings to the table that the ones above do not. It's kind of similar also to Jai which is also upcoming but focusing on game programming from what I understand... that's still not even publicly available yet.

Which one to choose really depends on your taste, hope my descriptions above help, even if they're pretty rough simplifications.

If you want the most popular language in this area, that's undoubtedly Rust though.

Re: Using Zig to Unit Test a C Application

#35
post #10
post #8

Earlier quoted context omitted.

Is ocaml a system language?

yes it can be used to create systems and backend tools - it is used to create an OS https://github.com/mirage - it is used to create a transpiler https://melange.re/v2.2.0/ - it was used to create Rust first compiler ocaml is surely a systems language

So sad IncludeOS https://github.com/includeos/IncludeOS is no longer developed.

Re: Using Zig to Unit Test a C Application

#36
This is interesting! I like how unit tests are easier with Zig.

The approach I am more familiar with is using Google test and C++ to test C code. It's pretty easy if you already have a cmake project set up, and most C developers can wrap their heads around GTest.

Re: Using Zig to Unit Test a C Application

#37

Earlier quoted context omitted.

Zig borrows some ideas from go. Probably defer is the big one, but if you watch "the road to zig 1.0" you will understand that zig is not really a go derivate. Most things in zig are directly addressing issues in c. If you squint zig's error return fusion looks a bit like go's tuple error return but it actually is more "first-classing certain c conventions" than "adopting a go pattern". Same goes for slices.

Most of C's issues were directly addressed in Go as well. Only, Go did away with manual memory management. C never had the philosophy of keeping things simple through the years. If it did, we would not have time traveling UBs to begin with. The lauded simplicity and explicitness comes directly from Go, where the philosophy was crystalized and preserved very early on. You might say it is semantics, to call improving u…

> The lauded simplicity and explicitness comes directly from Go

I have two words for you: json marshalling

Re: Using Zig to Unit Test a C Application

#38
post #4

zig , ocaml, odin many system languages are making the headlines lately its very hard to pick one to learn not sure how to deal with this, learn them all, bet on one, what should we do

> its very hard to pick one to learn

If you don't know it already, you learn C, as well as you can. It is not a hard language to learn, but it has a lot of footguns. That's why you learn it along with tools like Valgrind & sanitizers.

Then you look at Rust. That's somewhat harder to learn, but nails some important details you need to think about while writing C. It will make some things obvious that you'd need to learn by shooting yourself in the foot repeatedly in C. You don't need to use Rust once you got what you need out of it education-wise, but a lot of people like and use it.

At this point it is kind of unimportant what other "systems" language you decide to learn, but here's my opinion of some of them:

- Personally I like Odin's ergonomics. It is incredibly convenient. You can just jump in and start writing OpenGL code without dealing with wrappers and all that. Included vendor libraries take care of a lot.

- I also like the explicitness of Zig. It seems like it'll be the most popular one in the future, most likely not because of the language itself but because of the tooling. By the way the reason I say "not because of the language" is that the maintainers seem uninterested in having some way to constrain generics. The language sorely needs some sort of comptime interface / traits / concepts, anytype-everything is not nice. In 10 years someone will come up with a Boost-like library that implements just that in userspace and it'll be horrible.

- Ocaml is garbage collected Rust, or rather, Rust is non-garbage-collected Ocaml. It is underrated. Jane Street people are adding borrow checker to it. Could be more popular in the future. Also, all languages are "systems" languages depending on how you wield them. No need to bikeshed about Ocaml's "system"ness status.

- D is pretty cool. Very fragmented library ecosystem if you want to do betterC or no-gc though. Be prepared to just use C or C++ libraries, which it can talk to pretty easily.

- Nim is a nice language. Does reference counting so it has a low memory footprint compared to other GC'd languages. It compiles to C so technically it is the most portable language in this list. You can easily run it on microprocessors that others won't run on. Try it, you'll very quickly land on "like it" / "don't like it" territory depending on your programming style.

- Jai is non-existent right now. Doesn't warrant a discussion until Jon Blow feels it is ready for prime time. But since that's his strategy, expect something practical and polished. If it sucks, two possibilities: 1) he didn't deliver and it won't get drastically better or 2) your use case was not in consideration.

- C3, it exists, it is usable, it is like a halfway between C and D. I didn't spend much time on it yet.

- Free Pascal: I didn't use it but just putting it here because this list is getting long & it kind of deserves a shout. Lazarus looks nice.

- Go: Use Java or C# instead, they can compile to native now.

- C++: It exists, it is used everywhere, it sucks. As opposed to most other languages on this list, it wasn't designed. It kind of picked up random features along the way because they looked good. You kind of design it by picking up a subset and putting up with its weirdnesses. Don't use it if you can help it. If you have to use it you most likely didn't have a choice in the first place.

Re: Using Zig to Unit Test a C Application

#39
post #4

zig , ocaml, odin many system languages are making the headlines lately its very hard to pick one to learn not sure how to deal with this, learn them all, bet on one, what should we do

I've been having the same dilemma, right now my focus is:

- Typescript for anything related to webdev, not a huge fan of the language but can't deny the ecosystem for productivity

- Rust for systems-level projects

- Crystal for quick scripts, although I'm still on the fence here

Re: Using Zig to Unit Test a C Application

#40
Unit test it with TXR:

  $ pwd
  /home/kaz/ustreamer
  $ gcc -D_GNU_SOURCE -shared src/libs/base64.c -o base64.o
  $ valgrind txr --free-all
  ==8785== Memcheck, a memory error detector
  ==8785== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
  ==8785== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
  ==8785== Command: txr --free-all
  ==8785==
  This is the TXR Lisp interactive listener of TXR 292.
  Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet.
  Psst! The complimentary Allen key that comes with TXR is inpired by IKEA.
  1> (with-dyn-lib "./base64.o"
       (deffi us-base64-encode "us_base64_encode"
              void (buf size-t (ptr (array 1 str-d)) (ptr (array 1 size-t)))))
  us-base64-encode
  2> (let ((out (vec nil))
           (sz (vec 0)))
       (us-base64-encode #b'00112233445566778899AABBCCDDEEFF' 16 out sz)
       (list out sz))
  (#("ABEiM0RVZneImaq7zN3u/w==") #(25))
  3> (let ((out (vec "abcde"))
           (sz (vec 5)))
       (us-base64-encode #b'00112233445566778899AABBCCDDEEFF' 16 out sz)
       (list out sz))
  (#("ABEiM0RVZneImaq7zN3u/w==") #(25))
  4> (let ((out (vec "xxxxxxxxxxxxxxxxxxxxxxxxxx"))
           (sz (vec 25)))
       (us-base64-encode #b'00112233445566778899AABBCCDDEEFF' 16 out sz)
       (list out sz))
  (#("ABEiM0RVZneImaq7zN3u/w==") #(25))
  5> (let ((out (vec "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
           (sz (vec 27)))
       (us-base64-encode #b'00112233445566778899AABBCCDDEEFF' 16 out sz)
     (list out sz))
  (#("ABEiM0RVZneImaq7zN3u/w==") #(27))
  6>
  ==8785==
  ==8785== HEAP SUMMARY:
  ==8785==     in use at exit: 0 bytes in 0 blocks
  ==8785==   total heap usage: 24,782 allocs, 24,782 frees, 4,806,317 bytes allocated
  ==8785==
  ==8785== All heap blocks were freed -- no leaks are possible
  ==8785==
  ==8785== For counts of detected and suppressed errors, rerun with: -v
  ==8785== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
We covered the cases when the the destination buffer is already allocated, and smaller, equal to or in excess of the space being required. Thus testing the cases when realloc is or isn't necessary. No memory errors or leaks.

We can see in the last case that when the buffer is larger, the function leaves the size alone, returning our original 27.

Post reply on HN