C/C++
Run the C/C++
examples calling byexample
as:
$ byexample -l cpp your-file-here # byexample: +skip
To support C/C++, byexample
relays in the cling
interpreter.
You need to have cling installed first.
It is still an experimental feature that works pretty well but it is not immune to bugs, quirks nor crashes.
Don’t forget to send your feedback to the cling
community.
Stability:
experimental
- non backward compatibility changes are possible or even removal between versions (even patch versions).
Because installing and using cling
may be a little difficult, we
offer a docker image with cling
pre-installed (the
dockerfile
is available too).
To use the cling
in that docker image follow
the how to run with docker tutorial
which explains how to configure the host system and how to run
byexample
with an interpreter (cling
) which it is in a docker image.
Variable definition
All the variables are global and can be accessed by other examples
?: double radio = 2.0;
?: double sup = 3.14 * (radio * radio);
?: sup
(double) 12.56<...>
The last expression without ending with a ;
is interpreted by
cling
as the expression to not only evaluate but also to print its value.
stdlib
You can use the stdlib
as usual.
Here is an example of how to print something and check the output later:
?: #include <iostream>
?: int i;
?: for (i = 0; i < 3; ++i) {
:: std::cout << i << std::endl;
:: }
0
1
2
External libs
In addition to stdlib
you can add your own. These can be
in the form of C++ code and it will be compiled by cling
or in
the form of PIC, shared and dynamically linked library (aka, .so
)
For the first case you need to pass the path to the source code
with .L
or these pragma
?: #pragma cling load("test/ds/mylib1.cpp") // this will compile mylib1.cpp
?: #include "test/ds/mylib1.h" // the headers are needed to, as usual
?: mylib1_foo(2)
calling my lib1
(int) 4
For the second case, we need to compile the code ourselves:
$ g++ -shared -fPIC -o test/ds/libmylib2.so test/ds/mylib2.cpp # byexample: +timeout=16
The load then proceeds as before.
?: #pragma cling load("test/ds/libmylib2.so") // already compiled
?: #include "test/ds/mylib2.h" // the headers are needed to, as usual
?: mylib2_foo(2)
increased performance with lib2
(int) 6
We can define where to search for libraries and headers via two pragma
so we can avoid some typing
?: #pragma cling add_library_path("test/ds/")
?: #pragma cling add_include_path("test/ds/")
?: #pragma cling load("mylib3.cpp") // works for .so too
?: #include "mylib3.h"
?: mylib3_foo(2)
lib3, four times better
(int) 8
Note:
cling
is quite experimental and at least for the 0.6 version, it has not good diagnostic messages.If you find an error like
fatal error: 'libmylib2.so' file not found
it may indicate that you are not configuring the path correctly or that the library was not compiled as shared.Best way to troubleshoot is to use explicit paths to distinguish one error from the other.
If
cling
tries to load you shared library but it complains that it is not an UTF-8 valid file it means thatcling
is trying to see the library as source code. I found that this happen if the library is not compiled as a shared library.Double check with
file libmylib2.so
, you should see something likelibmylib2.so: ELF 64-bit LSB pie executable, ..., dynamically linked, ...
Running C code (and not C++)
cling
only supports C++ however it is possible to test C code
if it is compiled outside of cling
and loaded as a library.
$ gcc -std=c99 -shared -fPIC -o test/ds/libmylibC.so test/ds/mylibC.c # byexample: +timeout=16
?: #pragma cling load("test/ds/libmylibC.so") // C code
?: #include "test/ds/mylibC.h" // the declarations must be inside the extern "C" {...}
?: mylibC_foo(2)
(int) 3
While the examples will be running as C++ code, the function
mylibC_foo
was compiled as C code.
Keep in mind that the header mylibC.h
must have all the function
declarations inside extern "C" { ... }
so cling
will know that it
has to use the “C” calling convention and not the “C++” one.
See language linkage for reference.
Syntax errors
byexample
will show you the syntax errors detected by cling
.
You can even check for them as part of the normal output:
?: for (i = 0; i < unknown; ++i) {
:: std::cout << i << std::endl;
:: }
<...>: error: use of undeclared identifier 'unknown'
for (i = 0; i < unknown; ++i) {
^
Known limitations
Gotchas
To print boolean expressions you need to surround them with parenthesis
?: (1 == 2)
(bool) false
Terminal support
To work with the current C/C++ interpreter, cling
, the ANSI
terminal emulator is
enabled by default (+term=ansi
) and cannot be disabled.
Also, the terminal geometry is set to a default of 1024 columns and 2048 rows with a minimum of 128x128.
Changed: before
byexample 11.0.0
the runner was forced to use a 128x128 geometry without possibilities of change it. Since11.0.0
, the default is expanded to 2048x1024 and can be changed at any time but always with a minimum of 128x128.
Note: the minimum is enforced because if the snippet of C++ or the output is larger than the size of the terminal, the output will be undefined.
The default of 2048x1024 should be fine for most of the use cases.
Echoed input lines
If the C/C++ snippet has a very long line, greater than the terminal’s width, the last part of the line that does not fit in the terminal will be echoed in the output of the example.
This is an annoying artifact due how cling
works.
A simple workaround is to make the lines of the code in the snippet shorter or increase the terminal width.
Abort on a timeout
If a C/C++ example takes too long and timeout, the whole execution timeout.
Type text
The type
feature (+type
) is not supported.
C/C++ specific options
$ byexample -l cpp --show-options # byexample: +norm-ws
<...>
cpp's specific options
----------------------
None.