A N O V E R T U R E T O
C P R O G R A M M E R S
This preface is meant for experienced C
programmers who are considering whether
or not to read this book. Non–C program-
mers are welcome to skip this prelude.
Bjarne Stroustrup developed C++ from the C programming language.
Although C++ isn’t completely compatible with C,
well-written C programs
are often also valid C++ programs. Case in point, every example in
The C
Programming Language by Brian Kernighan and Dennis Ritchie is a legal
C++ program.
One primary reason for C’s ubiquity in the system-programming com-
munity is that C allows programmers to write at a higher level of abstraction
than assembly programming does. This tends to produce clearer,
less error-
prone, and more maintainable code.
Generally, system programmers aren’t willing to pay overhead for pro-
gramming convenience, so C adheres to the zero-overhead principle:
what
you don’t use, you don’t pay for. The strong type system is a prime example of
a zero-overhead abstraction. It’s used only at compile time to check for pro-
gram correctness. After compile time, the types will have disappeared, and
the emitted assembly code will show no trace of the type system.
A
rthur
D
ent
: What’s the matter with him?
h
ig
h
urtenflurst
: His feet are the wrong size for his shoes.
—Douglas Adams, The Hitchhiker’s
Guide
to the Galaxy,
“Fit the Eleventh
”
xxxviii
An Overture to C Programmers
As a descendant of C, C++ also takes zero-overhead abstraction and
direct mapping to hardware very seriously. This commitment goes beyond
just the C language features that C++ supports. Everything that C++ builds
on
top of C, including new language features, upholds these principles, and
departures from either are made very deliberately. In fact, some C++ features
incur even less overhead than corresponding C code. The
constexpr
keyword
is one such example. It instructs the compiler to evaluate the expression at
compile time (if possible), as shown in the program in Listing 1.
#include
constexpr int isqrt(int n) {
int i=1;
while (i*ireturn i-(i*i!=n);
}
int main() {
constexpr int x = isqrt(1764);
u
printf("%d", x);
}
Listing 1: A program illustrating
constexpr
The
isqrt
function computes the square root of the argument
n
. Starting
at
1
, the function increments the local variable
i
until
i*i
is greater than or
equal to
n
. If
i*i == n
, it returns
i
; otherwise, it returns
i-1
. Notice that the
invocation of
isqrt
has a literal value, so the compiler could theoretically
compute the result for you. The result will only ever take on one value
u
.
Compiling Listing 1 on GCC 8.3 targeting x86-64 with
-O2
yields the
assembly in Listing 2.
.LC0:
.string "%d"
main:
sub rsp, 8
mov esi, 42
u
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
xor eax, eax
add rsp, 8
ret
Listing 2: The assembly produced after compiling Listing 1
The salient result here is the second instruction in
main
u
; rather than
evaluating the square root of
1764
at runtime, the compiler evaluates it and
outputs instructions to treat
x
as
42
. Of course, you could calculate the square
root using a calculator and insert the result manually, but using
constexpr
pro-
vides lots of benefits. This approach can mitigate many errors associated with
manually copying and pasting, and it makes your code more expressive.
An Overture to C Programmers
Dostları ilə paylaş: