Multiple definitions of inline function

In C++, a function is annotated with inline to implore the compiler to inline that function’s code into its callers. The C++ standard says that injecting multiple differing definitions of an inline function into a program is illegal because it breaks the ODR.

For example, ยง7.1.2 from the C++11 standard says:

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case.

So, having multiple differing definitions is illegal but the compiler cannot really stop it. This is because two differing definitions of the same inline method might be inlined into their callers in two different compilation units that are linked together into a program.

Thus, if we use multiple different inline definitions, all bets are off and it is undefined behavior.

This example illustrates the final behavior differs based on just compilation flags:

// x.cpp
#include <iostream>

inline void f()
{
    std::cout << __FILE__ << std::endl;
}

extern void g();

int main()
{
    f();
    g();

    return 0;
}

// y.cpp
#include <iostream>

inline void f()
{
    std::cout << __FILE__ << std::endl;
}

void g()
{
    f();
}

$ g++ x.cpp y.cpp
$ ./a.out
x.cpp
x.cpp

$ g++ -O2 x.cpp y.cpp
$ ./a.out
x.cpp
y.cpp

If we want to control and want each caller to only use its local inline definition, then we can do that by placing the inline method inside an anonymous namespace. The practice of multiple differing inline definitions is still illegal, but at least we now have controlled what happens. This example illustrates this:

// x.cpp
#include <iostream>

namespace
{
inline void f()
{
    std::cout << __FILE__ << std::endl;
}
}

extern void g();

int main()
{
    f();
    g();

    return 0;
}
                                                                                                                                                                                // y.cpp
#include <iostream>

namespace
{
inline void f()
{
    std::cout << __FILE__ << std::endl;
}
}

void g()
{
    f();
}

$ g++ x.cpp y.cpp
$ ./a.out
x.cpp
y.cpp

$ g++ -O2 x.cpp y.cpp
$ ./a.out
x.cpp
y.cpp

Thanks to Arch for the elegant examples.

Advertisements

Programming the 8086/8088

Programming the 8086/8088

Recently I was looking at PCJs, which does a classic IBM PC simulation in your browser. In its Programming Guides list I discovered this book about the classic 8086: Programming the 8086/8088 by James W. Coffron. The first assembly language I learned almost two decades ago was the 8086. The x86 and x86-64 assembly language got so bloated and complicated after that. I picked up this book to relive that feel of a simple processor whose entire architecture and details you could actually comprehend.

This book seems to be meant for anyone with a bit of programming experience. The 8086 and 8088 architecture is introduced first, followed by details of its registers, instructions, memory model, I/O and how to program for it. There is a complete reference of its instructions, which are shockingly few in number for a CISC processor. It was quaint to see a listing of the number of cycles each instruction would take. (The fastest instructions took ~3 cycles and the slowest like integer division took hundreds of cycles.) Notably missing was floating point, which this early processor did not support, you had to use a math co-processor for that.

Studying the book I was reminded of how these Intel processors differed from others. The 8088 was introduced as a cheaper 8086. Both operated at 16-bit with 16-bit registers and a 20-bit address bus. The only difference was that 8088 had a 8-bit data bus and the 8086 had a 16-bit data bus. These processors supported another bygone relic: segmented memory. One of the segment registers holding a segment base address was right-shifted by 4 bits and added to offset address from another register to generate the 20-bit address. A final oddity was that 8086/8088 did not do memory mapped I/O, instead you used IN and OUT instructions to read from IO ports.

The book was pretty easy to follow along and covered both 8086 and 8088 well. Almost all aspects of the processors seem to be covered. What nagged me were several small mistakes that I could notice in the book. Maybe another round of proofreading would have helped. This book was easy, but I am still looking for the perfect 8086 reference.

Rating: 3/4 (โ˜…โ˜…โ˜…โ˜†)

How to install PDFTK

PDFTK is a tool that can be used to split and merge PDF files. It is available for both Linux and Windows.

Windows

PDFTK installer for Windows can be downloaded here. After PDFTK is installed, ensure that the directory of pdftk.exe is in the PATH environment variable.

Ubuntu 18.04 and newer

For Ubuntu versions starting from 18.04 and newer versions, use Snap to install PDFTK:

$ sudo snap install pdftk

Ubuntu 16.04 and older

For Ubuntu versions 16.04 and older versions, use Apt to install PDFTK:

$ sudo apt install pdftk

If your installation is successful, you should be able to run pdftk from the shell.

How to use Vim as plain text editor

Vim is not only useful for code, but also as a general plain text editor. This is useful for writing README files, Markdown files or if you like publishing plain text file content.

In plain text files, a desirable property is to have lines wrapped at a certain width. The general wrap feature of Vim is meaningful only for code which has long lines. This option just wraps the long line visually to the screen width.

To use Vim as a plain text editor you want it to automatically breaks lines at a certain width as you type. You want it to do that only at word boundaries. The option that enables this mode is textwidth. For source code, this feature is disabled and is set to 0.

To enable Vim to set a maximum width for text that is inserted, set this option: :set textwidth=80

If you have existing text that was not set to this width or you have shortened some lines all of that can be fixed too: mark them visually and press gq.

A final feature needed from a plain text editor is to be able to center a line. This is useful for example for titles and section headings. To do that, mark that line visually and type :center. This only works if the textwidth option is set.

Tried with: Vim 8.0 and Ubuntu 18.04

How to use clang-tidy

clang-tidy is a LLVM tool that can be used as a static checker on your C++ codebase and to fix errors it finds. A full list of current checks and their descriptions can be found here. The number of checks available to you will depend on the clang-tidy version you are using.

  • Installing this tool is easy:
$ sudo apt install clang-tidy

This typically installs a stable but older version of the tool with less number of checks.

  • To list the checks it performs by default:
$ clang-tidy -list-checks

On my computer I found it had 80 checks enabled by default.

  • To list all the checks that it can perform:
$ clang-tidy -list-checks -checks="*"

On my computer I found that it had a total of 292 checks.

  • To check a file using all checks enabled by default:
$ clang-tidy foobar.cpp
  • To check a file using all checks enabled by default and fix the errors using suggested fixes:
$ clang-tidy -fix foobar.cpp
$ clang-tidy -fix-errors foobar.cpp
  • To use a specific check, say modernize-use-nullptr:
$ clang-tidy -checks="-*,modernize-use-nullptr" foobar.cpp

Tried with: clang-tidy 6.0.0 and Ubuntu 18.04

How to fix header guards using guardonce

Header guards are used in C and C++ header files to avoid them being included more than once during the compilation of a compilation unit. There are generally two techniques: using an include guard and using a pragma once directive. guardonce provides a set of Python tools that can be used to diagnose the state of header guards, convert between the two types of guards and to fix guards in your codebase.

  • Installing guardonce using pip is easy:
$ sudo pip3 install guardonce
  • To convert include guards to pragma onces for all header files in the current directory:
$ guard2once *.h
  • To convert pragma onces to include guards for all header files in the current directory:
$ once2guard *.h
  • The tools support a pattern language that can be used to specify include guard name of a specific pattern. The pattern is built like a Unix pipeline. For example, to convert pragma once to include guard names with a default prefix (say FOOBAR_) followed by filename in snake form and uppercase:
$ once2guard -p "name | snake | upper | prepend FOOBAR_" *.h

For a filename linkedList.h the above command would generate an include guard name FOOBAR_LINKED_LIST_H.

  • For include guards it is convenient to have the guard name to appear in comments near the endif. To do that:
$ once2guard -s "#endif // %" *.h
  • It is a good convenience to have a newline before the endif. To do that:
$ once2guard -l *.h
  • There is no straightforward option to fix or modify the include guards to a certain pattern. Instead I found that I could achieve this by first converting the file to pragma once and then converting back to include guards. This can be done like this:
$ guard2once *.h ; once2guard *.h

Tried with: guardonce 2.4.0 and Ubuntu 18.04

Unix date tool

date is the Unix tool to check both the date and the time from the shell in Linux, Cygwin and other Unix-like systems. There is no separate tool to show the time. date is part of the GNU Coreutils package.

  • By default, the tool displays the local time in your local format. On my computer, the format was like this:
$ date
Mon, Jan 21, 2019  8:42:23 AM
  • To view the UTC time:
$ date -u
  • To view the modification time of a file:
$ date -r foobar.txt

How to get last argument of previous command in Fish

While working at the Bash shell prompt, you can access the very last argument of the preceding command using $_.

For example:

$ vim foobar.txt
$ vim $_

To get the effect of $_ in Fish, press Alt+Up. Fish will insert the last argument of the previous command for you right there at the shell prompt.

If you find this command is not working, please check if your terminal multiplexer (tmux or Byobu) or your GUI terminal or windowing environment has not already assigned that key for something else.

How to copy retaining relative path

Problem

From a certain directory I wanted to copy a file a/b/c.txt to a destination. But I wanted the relative path a/b to be retained at the destination. A normal copy would just copy c.txt to the destination.

Solution

There is no way to do this using the cp command. One solution is to use rsync which supports maintaining the relative file path.

For example:

$ pwd
/home/joe/workspace/foobar
$ rsync -R a/b/c.txt /home/joe/destination

This copies c.txt to /home/joe/destination/a/b automatically creating a/b if they do not exist in the destination.

Embedded Software Development for Safety-Critical Systems

Chris Hobbs is a safety engineer who works on the QNX real-time operating system. I discovered him while reading QNX documentation and that led to reading his book Embedded Software Development for Safety-Critical Systems. This book is a practical introduction for software engineers who need to develop software that is compliant to functional safety standards such as IEC 61508 and ISO 26262.

I picked up the book precisely because these IEC/ISO standards are incredibly hard to digest. This book turned out to be truly a breath of fresh air. It cut through so much of the jargon used in the above standards giving simple and elegant meanings and illustrations for all of them. For example, normal English words like fault, error and failure have distinct and precise meanings in the safety world. And when reading and writing in this space one needs to be clearly aware of these meanings.

The author has loads of experience in the safety systems field and that helps when he gives his personal opinion of many of the recommendations and procedures set forth by these standards. There is a large section of the book given to fault analysis and formal verification which I am not sure how most software would undergo.

Minor quibbles aside, I found this book to be truly enlightening and only wished it was longer and covered more of the software development process for general and more complex software that cannot undergo formal verification. If you are looking to comply to standards such as IEC/ISO this book seems like a perfect no-nonsense introductory text.