C-for-Golang: Using C & C++ in Golang
Date Published
Reading time
5 min
In this article
Your team has decided on Go after months of months of developing modules and roadmapping for a large project, but since there are three external dependencies in C/C++, your entire project will now have to be done in C/C++. What does this mean? Now, at least half of your development time will be spent correcting memory accesses bugs and invalid cast errors -- and not many developers can afford to allocate this time. What can be done to expedite this process?
Maxim Kupriianov, a Senior Go Engineer at
Sphere Software
, first formulated an assistant tool called C-for-Go used to create CGo bindings of C libraries to use in his
applications. “The idea was to scan the provided C header files for structs, types, and function definitions, and
then convert their names into idiomatic Go names, preparing boilerplate code for CGo calls, and so on,” he said.
After discovering the czinc/cc package, Maxim’s project would soon become
a full-featured binding generator, allowing developers who would like to use any C library in their code to do so in
less than one hour -- all without writing a single line of code.
Golang’s C and C++ binding
generator changed everything.
The sole purpose of C-for-Go is to bring a substantial boost in a developer’s productivity and overall system performance.
C-for-GoLang Process Overview
C-for-Golang allows to reuse existing C/C++ libraries in your Go applications by automatically generating c-go bindings
for a given set of C headers and the manifest file. Below is an overview of this process:
The only component required to produce a Go package that will wrap the source C/C++ code is the YAML manifest file
that defines parsing, translation, and generation rules. The manifest only requires a few lines, however, in order
to match Go's naming conventions and provide enough tips for type conversions, it usually contains about 100 lines.
Overall, this is much less time consuming than producing tens-of-thousands of lines of Go code by hand.
The resulting bindings are as low-level as C code. It would require knowledge of memory management to carefully use
the resulting code, however, no more C code is needed to finish this process. Eventually, some functions can be
replaced manually with pure-Go analogs. Also, high-level wrappers are usually created by hand to introduce Object
Oriented Design into API, manage inner state, and memory -- increasing safety and lifting the mental overhead.
Architecture of C-for-GoLang
C-for-Go consists of three parts: The translator, generator, and parser -- in order of importance.
- Translator - Responsible for name conversions. The translator does a bulk of the C-for-Go work -- with parts of its engine including name substitution, rule patterns, hints/tips for type conversions.
- Generator - The generator is based on fmt.Sprintf mechanism and that helped a lot to avoid code bloat. Also, the generator is very flexible. For example, when Go 1.6 announced pointer rules, the required changes included switching all allocations to C.malloc calls, having a reference count object, implementing pointer borrowing, automating frees with finalizers, and nesting allocations while unpacking slices. This was all added to the generator in a few days.
- Parser - The parser is actually a wrapper for cznic/cc C99 compiler front-end. By coincidence, it was under active development at the same time as C-for-Go. Parser is configured partly from the configuration manifest and partly from predefined options in predefined.go.
The main executable provides the glue for all of three modules. It does config parsing, runs external utils like
in-house pkg-config lightweight clone to discover more headers, manages the output buffers, formats the code using
imports, process after generation is done, and so on.
Consideration for Bindings
What would motivate a developer to use golang c++ bindings instead of writing a pure-Go package with the same functionality?
Here are a few arguments:
- Rewriting Difficulty with Old Tech
- Even many of today’s technologies, including C/C++, have roots in old technologies. Let’s consider how a developer would rewrite the Qt Framework? The libvpx from the WebM project? Among technologies that difficult to rewrite, there are many with nothing to rewrite at all. Native adapters for various system drivers like PortAudio or PortMIDI that are meant to be portable and support dozens of OSes and environment configurations are some examples. If a good C library is worth a pure-Go rewrite, consider getting a quick binding set, write your tests, and then rewrite the library piece-by-piece.
- Rewriting Difficulty with Modern Tech
- What about modern APIs being auto-generated from language-agnostic XML specs like Vulkan Graphics API? There’s nothing to rewrite in Go, because this API provides no implementation in user space either. Let’s face it, nobody will be able to “rewrite” reentrant wrappers for old heritage libraries because the main action goes in the heritage code -- which acts like an anchor. If this thin wrapper allows you to run that code on Android/iOS platforms, why not bring that into Go?
- Performance Increase
- Since Go 1.5, there have been significant penalties for calling CGo too frequently. However, the amount of calls needed to get the job done vary from domain to domain. Some C libraries maxed out the amount of tricks used to increase performance like custom allocators, zero-copy buffers, efficient data types, and so on. With the new SSA additions and runtime improvements, Go may perform even better than C -- especially with all the not-so-thin CGo wrappers and validators around the C API.
C-for-GoLang Demo and More
To see how to utilize C-for-Golang, filling the generator, adding the parser and translator preferences, and more,
visit Sphere Software’s Github/c-for-go. C-for-Go is free to use, free to
distribute, and free to fork under the MIT license. However, Sphere Software also provides professional services to
help companies reuse C/C++ components in their Go applications. This consists of composing the manifest, consulting
about the best workflows with C-Go bindings, verifying, and improving the resulting Go packages.
Contact
our experienced team if you have any questions about using
C and C++ in GoLang
. We provi
de
software development services
,
on-demand IT services
,
enterprise platform solutions
, and much more.
More to read

Dive into Sphere's full-stack developer journey with AI – from tackling code with GitHub Copilot to unleashing problem-solving insights with ChatGPT. Explore the potential of AI in software development projects: which tools are truly handy, how many hours can you save, and what's the next big thing? Pavel Korchak shares his insights.

In 2023, interoperability is still top of the agenda for leaders and decision-makers, referring to the timely and secure access, integration and use of electronic health data to optimize health outcomes for individuals and populations.

As the founder and CEO of a global technology consulting and software engineering firm, here’s another reality of modern business I see far too often: Most products that companies say they’re developing are really just projects.

There are six surefire signals that point to it being time to pivot from monolithic architecture to microservices or modular architecture.
