C/C++

boost::lexical_cast minimal example

#include <boost/lexical_cast.hpp>
#include <iostream>

int main() {
    int a = boost::lexical_cast<int>("123");
    int b = boost::lexical_cast<int>("456");
    
    int c = a + b;
    std::cout << c << std::endl; //Prints 579
}

 

Posted by Uli Köhler in Boost, C/C++

Computing distance between gp_Pnt and gp_Ax1 in OpenCASCADE

OCCUtils provides convenience functions for computing the orthogonal direction to two directions:

#include <occutils/Axis.hxx>
using namespace OCCUtils;

gp_Ax1 axis = /* ... */;
gp_Pnt pnt = /* ... */;
double distance = Axis::Distance(axis, pnt);

Alternatively, you can also use Point::Distance() which internally just calls Axis::Distance() but might make your code more readable under some circumstances. Note that the argument order is inverted!

#include <occutils/Point.hxx>
using namespace OCCUtils;

gp_Ax1 axis = /* ... */;
gp_Pnt pnt = /* ... */;
double distance = Point::Distance(pnt, axis);

In case you can’t use OCCUtils, here’s the code to do it manually:

double distance = gp_Lin(axis).Distance(pnt);
Posted by Uli Köhler in C/C++, OpenCASCADE

How to check if gp_Ax1 contains gp_Pnt in OpenCASCADE

OCCUtils provides convenience functions for computing the orthogonal direction to two directions:

#include <occutils/Axis.hxx>
using namespace OCCUtils;

gp_Ax1 axis = /* ... */;
gp_Png point = /* ... */;
bool pointIsOnAxis = Axis::Contains(axis, point);

In case you can’t use OCCUtils, here’s the code to do it manually:

gp_Lin(axis).Contains(pnt, Precision::Confusion());
Posted by Uli Köhler in C/C++, OpenCASCADE

How to get gp_Dir orthogonal to two gp_Dirs in OpenCASCADE

OCCUtils provides convenience functions for computing the orthogonal direction to two directions:

#include <occutils/Direction.hxx>
using namespace OCCUtils;

gp_Dir dir1 = /* ... */;
gp_Dir dir2 = /* ... */;
gp_Dir orthogonalDirection = Direction::Orthogonal(dir1, dir2);

In case you can’t use OCCUtils, here’s the code to do it manually:

gp_Dir orthogonalDirection = dir1.Crossed(dir2);

The function used is called Crossed() since the mathematical operation being used is the cross product between the two direction vectors.

 

Posted by Uli Köhler in C/C++, OpenCASCADE

How to get midpoint/center between points in OpenCASCADE

OCCUtils provides convenience functions for getting the midpoint (also called the center) between 2 or more points:

#include <occutils/Point.hxx>
using namespace OCCUtils;

gp_Pnt p1 = /* ... */;
gp_Pnt p2 = /* ... */;
gp_Pnt midpointOfP1AndP2 = Point::Midpoint({p1, p2});

You can also call Point::Midpoint() with a std::vector<gp_Pnt>.

In case you can’t use OCCUtils, here’s the code to do it manually:

double x = 0.0, y = 0.0, z = 0.0;
for (const gp_Pnt &pnt : points) {
    x += pnt.X();
    y += pnt.Y();
    z += pnt.Z();
}
size_t size = points.size();
gp_Pnt midpoint(x / size, y / size, z / size);

 

 

Posted by Uli Köhler in C/C++, OpenCASCADE

How to compute volume of TopoDS_Shape / TopoDS_Solid in OpenCASCADE

OCCUtils provides a convenience function to do this:

#include <occutils/Shape.hxx>

using namespace OCCUtils;

TopoDS_Shape myShape = /* ... */;

double volume = Shape::Volume(myShape);

In case you need to do this without OCCUtils, use

GProp_GProps gprops;
BRepGProp::VolumeProperties(shape, gprops);
double volume = gprops.Mass();

 

Posted by Uli Köhler in C/C++, OpenCASCADE

Towards a docker-based build of C/C++ applications

Note: Based on this post I have published buildock on GitHub.

Many C/C++ programmers and project managers know the pain of creating a reproducible build environment for all developers: Works for me is a common meme not without a reason.

My approach is to dockerize not neccessarily the application itself but the build system, encapsulating both the specific compiler version and the system around it plus all required system-level libraries in a Docker image.

Take the obligatory Hello World in C++:

// main.cpp
#include <iostream>
using namespace std;

int main() {
    cout << "Hello, World!" << endl;
    return 0;
}

and the corresponding Makefile:

all:
        g++ -o helloworld main.cpp

How can we compile this simple project without installing a compiler and GNU make on the local computer (no cheating by using build servers allowed)?

Actually it’s rather simple:

docker run --user $(id -u):$(id -g) -v $PWD:/app -it ulikoehler/ubuntu-gcc-make make

Breaking it down:

  • docker run: Create a new docker container and run a command in it
  • --user $(id -u):$(id -g): This makes the docker container run with the current user’s ID and the current user’s group – both for preventing the compiler to create output files as root and to safeguard against some IT security risks. Also see How to run docker container as current user & group
  • -v $PWD:/app: Mount the current directory ($PWD) on /app in the container. Since the Dockerfile used to build the container contains the WORKDIR /app directive, whatever command we run in the container will by default be executed in the /app directory – and therefore in the current local directory on the host.
  • -it runs the container in interactive mode, i.e. keypressed are passed down to the command you are running. Also, this means that our command will only finish when the container has finished executing.
  • ulikoehler/ubuntu-gcc-make: This is the image we’re using for that example. It’s nothing more than an ubuntu:18.04 base image with build-essentials and make installed and WORKDIR set to /app
  • make: This is the command we’ll run in the container. You can use any command here, even no command is possible (in which case the container’s default command will be used – in case of ulikoehler/ubuntu-gcc-make that is CMD [ "/usr/bin/make" ])

Here’s the complete Dockerfile used to generate ulikoehler/ubuntu-gcc-make:

FROM ubuntu:18.04
RUN apt update && apt -y install build-essential make && rm -rf /var/lib/apt/lists/*
WORKDIR /app
CMD [ "/usr/bin/make" ]
Posted by Uli Köhler in Build systems, C/C++, Container, Docker

How to compute surface normal in OpenCASCADE

OCCUtils provides a convenient utility to compute the Normal of a surface (represented by a GeomAdaptor_Surface) in OpenCASCADE:

#include <occutils/Surface.hxx>

using namespace OCCUtils;

GeomAdaptor_Surface surf = /* ... */;

gp_Ax1 surfaceNormal = Surface::Normal(surf);

// ...or just get the direction
gp_Dir surfaceDirection = Surface::NormalDirection(surf);

This function computes the normal vector at specific U/V coordinates which default to (0,0). You can also give custom U/V coordinates:

gp_Ax1 normal = Surface::Normal(surf, 1.0 /* u */, -4.5 /* v */);

In case you can’t use OCCUtils and you need to do it manually, here’s how you can do it:

#include <GeomLProp_SLProps.hxx>

GeomLProp_SLProps props(surf.Surface(), u, v, 1 /* max 1 derivation */, precision);
gp_Ax1 axis(props.Value(), props.Normal());

props.Value() returns the point on the surface at the given U/V coordinates.

Posted by Uli Köhler in C/C++, OpenCASCADE

How to fix C++ ‘fatal error: stringstream: No such file or directory’

Problem:

Your C++ code contains a line like

#include <stringstream>

since you want to use std::stringstream, but your compiler gives you this error message:

main.cpp:2:10: fatal error: stringstream: No such file or directory
 #include <stringstream>
          ^~~~~~~~~~~~~~
compilation terminated.

Solution:

The header is called sstream, not stringstream! Use this #include directive instead:

#include <sstream>
Posted by Uli Köhler in C/C++, GCC errors

How to parse hex strings in C++ using std::stringstream

This function converts any hex string like 55 to its equivalent decimal value:

#include <sstream>
#include <int>

unsigned int hexToDec(const std::string& str) {
    unsigned int ret;
    std::stringstream ss;
    ss << std::hex << str;
    ss >> ret;
    return ret;
}

e.g.

hexToDec("55"); // returns 85

Note that while the code is somewhat concise, it might be neither the most performant nor the most concise option especially for developers that don’t really know std::stringstream.

Posted by Uli Köhler in C/C++

How to get first three characters of std::string in C++

To get the first three characters of myString use myString.substr() like this:

std::string firstTwo = myString.substr(0, 3);

The first argument ob substr() is the offset (i.e. how many characters to skip) which is 0 in this case since we don’t want to skip any characters.

The second argument of substr() is the number of characters to get. Since we want to get three characters, this is 3.

Posted by Uli Köhler in C/C++

How to get first two characters of std::string in C++

To get the first two characters of myString use myString.substr() like this:

std::string firstTwo = myString.substr(0, 2);

The first argument ob substr() is the offset (i.e. how many characters to skip) which is 0 in this case since we don’t want to skip any characters.

The second argument of substr() is the number of characters to get. Since we want to get two characters, this is 2.

Posted by Uli Köhler in C/C++

C++ std::string equivalent to Python’s rstrip

In Python you can do

"test ".rstrip()

whereas in C++ the easiest way is to use the the Boost String Algorithms library:

#include <boost/algorithm/string/trim.hpp>

using namespace boost::algorithm;

string to_trim = "test ";
string trimmed = trim_right_copy(to_trim);

_copy in trim_right_copy() means that the original string is not modified.

Full example:

#include <iostream>
#include <string>
#include <boost/algorithm/string/trim.hpp>

using namespace std;
using namespace boost::algorithm;

int main() {
    string to_trim = "test ";
    string trimmed = trim_right_copy(to_trim);
    cout << trimmed << endl; // Prints 'test'
}

In case you want to trim a custom set of characters, use trim_right_copy_if() together with is_any_of():

#include <iostream>
#include <string>
#include <boost/algorithm/string/trim.hpp>

using namespace std;
using namespace boost::algorithm;

int main() {
    string to_trim = "testXbbca";
    string trimmed = trim_right_copy_if(to_trim, is_any_of("abc"));
    cout << trimmed << endl; // Prints 'testX'
}

 

Posted by Uli Köhler in C/C++

C++ std::string equivalent to Python’s lstrip

In Python you can do

" test".lstrip()

whereas in C++ the easiest way is to use the the Boost String Algorithms library:

#include <boost/algorithm/string/trim.hpp>

using namespace boost::algorithm;

string to_trim = " test";
string trimmed = trim_left_copy(to_trim);

_copy in trim_left_copy() means that the original string is not modified.

Full example:

#include <iostream>
#include <string>
#include <boost/algorithm/string/trim.hpp>

using namespace std;
using namespace boost::algorithm;

int main() {
    string to_trim = " test";
    string trimmed = trim_left_copy(to_trim);
    cout << trimmed << endl; // Prints 'test'
}

In case you want to trim a custom set of characters, use trim_left_copy_if() together with is_any_of():

#include <iostream>
#include <string>
#include <boost/algorithm/string/trim.hpp>

using namespace std;
using namespace boost::algorithm;

int main() {
    string to_trim = "bbcaXtest";
    string trimmed = trim_left_copy_if(to_trim, is_any_of("abc"));
    cout << trimmed << endl; // Prints 'Xtest'
}

 

Posted by Uli Köhler in C/C++

How to fix undeclared O_RDONLY/O_RDWR/O_WRONLY in C

Problem:

You are trying to compile C sourcecode that uses open(), but you see a compiler error message like this:

main.c: In function ‘main’:
main.c:3:14: warning: implicit declaration of function ‘open’ [-Wimplicit-function-declaration]
     int fd = open("my.txt", O_RDONLY);
              ^~~~
main.c:3:29: error: ‘O_RDONLY’ undeclared (first use in this function)
     int fd = open("my.txt", O_RDONLY);
                             ^~~~~~~~
main.c:3:29: note: each undeclared identifier is reported only once for each function it appears in

or

main.c: In function ‘main’:
main.c:3:14: warning: implicit declaration of function ‘open’ [-Wimplicit-function-declaration]
     int fd = open("my.txt", O_RDWR);
              ^~~~
main.c:3:29: error: ‘O_RDWR’ undeclared (first use in this function)
     int fd = open("my.txt", O_RDWR);
                             ^~~~~~
main.c:3:29: note: each undeclared identifier is reported only once for each function it appears in

or

main.c: In function ‘main’:
main.c:3:14: warning: implicit declaration of function ‘open’ [-Wimplicit-function-declaration]
     int fd = open("my.txt", O_WRONLY);
              ^~~~
main.c:3:29: error: ‘O_WRONLY’ undeclared (first use in this function)
     int fd = open("my.txt", O_WRONLY);
                             ^~~~~~~~
main.c:3:29: note: each undeclared identifier is reported only once for each function it appears in

Solution:

Add

#include <fcntl.h>

to the top of the source file where the error occured.

The POSIX header fcntl.h includes the definitions for O_RDONLY, O_RDWR and O_WRONLY amongst other POSIX-related definitions.

Also, this will include the definition for open() itself, which is missing as well – this is indicated by this line in the error message:

main.c:3:14: warning: implicit declaration of function ‘open’ [-Wimplicit-function-declaration]

See the OpenGroup reference on fcntl.h for more details on what else is defined in fcntl.h and what the meaning of all the individual flags is.

Posted by Uli Köhler in C/C++, GCC errors

Minimal pthread mutex example

#include <pthread.h>
int main() {
    // Create mutex
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL /* default mutex attributes */);
    // Lock
    pthread_mutex_lock(&mutex);
    // Unlock
    pthread_mutex_unlock(&mutex);
    // Cleanup
    pthread_mutex_destroy(&mutex);
}

Compile like this:

gcc -o main main.c -pthread
Posted by Uli Köhler in C/C++

How to fix C warning ‘implicit declaration of function _exit’

Problem:

You have C code like

_exit(1);

but when you try to compile it you see a warning message like

main.c: In function ‘main’:
main.c:3:5: warning: implicit declaration of function ‘_exit’ [-Wimplicit-function-declaration]
     _exit(1);
     ^~~~~
main.c:3:5: warning: incompatible implicit declaration of built-in function ‘_exit’

Solution:

Add

#include <unistd.h>

at the top of the source file where the error occured.

Note that in case you use _Exit(...) (capital E) instead of _exit(...), you need to add

#include <stdlib.h>

instead.

Read the manpage for _exit in case you need further information on _exit(...).

Posted by Uli Köhler in C/C++, GCC errors

How to fix C error ‘RTLD_NEXT undeclared’

Problem:

You have C code like

dlsym(RTLD_NEXT, 'myfunc');

but when you try to compile it you see an error message like

main.c:3:11: error: ‘RTLD_NEXT’ undeclared (first use in this function)
     dlsym(RTLD_NEXT, 'myfunc');
           ^~~~~~~~~

Solution:

Add

#define _GNU_SOURCE
#include <dlfcn.h>

at the top of the source file where the error occured.

In order for RTLD_NEXT to be declared, #define _GNU_SOURCE must occur before the first #include statement!

Posted by Uli Köhler in C/C++, GCC errors

How to fix C warning ‘implicit declaration of function dlsym’

Problem:

You have C code like

dlsym(RTLD_NEXT, 'myfunc');

but when you try to compile it you see a warning message like

main.c: In function ‘main’:
main.c:3:5: warning: implicit declaration of function ‘dlsym’ [-Wimplicit-function-declaration]
     dlsym(RTLD_NEXT, 'myfunc');

Solution:

Add

#include <dlfcn.h>

at the top of the source file where the error occured. This will include both dlopen, dlsym and related definitions like RTLD_NEXT.

Posted by Uli Köhler in C/C++, GCC errors

How to fix C error ‘unknown type name intptr_t’

Problem:

You have C code like

int v = 123;
intptr_t vptr = (intptr_t)&v;

but when you try to compile it you see an error message like

main.c: In function ‘main’:
main.c:5:1: error: unknown type name ‘intptr_t’; did you mean ‘__int128_t’?
 intptr_t vptr = (intptr_t)&v;
 ^~~~~~~~
 __int128_t
main.c:5:18: error: ‘intptr_t’ undeclared (first use in this function)
 intptr_t vptr = (intptr_t)&v;
                  ^~~~~~~~
main.c:5:18: note: each undeclared identifier is reported only once for each function it appears in

Solution:

Add

#include <stdint.h>

at the top of the source file where the error occured.

Posted by Uli Köhler in C/C++, GCC errors