Making the most of your Shells History on Linux and macOS

Modern UNIX shells like bash (default on Linux) and zsh (default on macOS) keep a history of all the commands you enter. The easiest way to access this history is by pressing the up and down cursor keys to browse through the last commands.

But this is only the tip of the iceberg. There are many more powerful history features that are easy to overlook. Learning them and making them second nature will help you to become much faster with a shell.

Viewing the History

The full history can be printed with the history command:

$ history
100 cd
101 vim file.txt
102 ls
103 mount
104 cat /etc/fstab
$
Continue reading “Making the most of your Shells History on Linux and macOS”

The Anomaly of the char Type in C

When we declare a variable of type int and we don’t tell the compiler if it is supposed to be signed or unsigned it is signed by default:

signed int s_number;   // signed
unsigned int u_number; // unsigned
int number; // equivalent with signed int

This is true for all integer number types (short, int, long, long long).

But there is one exception: The char type!

The char Type is Special

According to the C Standard, it depends on the implementation if char is signed or unsigned. The standard also says that char doesn’t collapse into one of signed char or unsigned char but is considered its own type (although it is represented internally as signed or unsigned, of course).

But the most surprising thing to know about char is that it is not guaranteed to be 8 bits. That means the C Standard does not guarantee a byte to be 8 bits. There are some very old architectures where char is 9 bits wide for example.

Fortunately for us, basically all architectures in use today have bytes that are 8 bits wide. Still, a program that assumes char to be 8 bits wide will not be portable to every platform where a C compiler is available.

Ask the Compiler

The characteristics of the char type (as well as all other types) are exposed in the standard header file limits.h. Therefore we can write a simple C program to find out how char is implemented on our platform:

#include <stdio.h>
#include <limits.h>

int main(void)
{
    printf("char bits:         %d\n", CHAR_BIT);
    printf("char is:           %s\n", CHAR_MIN < 0 ? "signed" : "unsigned");
    printf("signed char min:   %d\n", SCHAR_MIN);
    printf("signed char max:   %d\n", SCHAR_MAX);
    printf("unsigned char min: 0\n");
    printf("unsigned char max: %d\n", UCHAR_MAX);

    return 0;
}
Continue reading “The Anomaly of the char Type in C”

How to Create a Modern C Project with CMake and Conan

The C programming language is over 50 years old. Despite its age, it is still going strong. Many languages have tried to replace it. But so far none did succeed. To this very day, C is still the foundation on which all the software we use each and every day ultimately depends.

But with such a long history it comes as no surprise that there are a lot of legacy C projects out there. Projects that use outdated build systems and outdated practices. This is really a shame because, in this day and age, we have many awesome new tools at our fingertips that can help us tremendously when it comes to writing better and more robust C code.

So what if we would start a new C project from scratch today? How would we structure it? How would we build it? And what tools and features would we integrate into the build system from the start?

There are many possible answers to this question but in this article, I want to give you mine. And that’s why we are going to build the template of a modern C project from scratch. There will be code and it will compile into an executable but our main focus will be on the build system.

Continue reading “How to Create a Modern C Project with CMake and Conan”