The purpose of this tutorial is to get an experienced Python programmer up to speed with the basics of the C language and how it’s used in the CPython source code. It assumes you already have an intermediate understanding of Python syntax.
That said, C is a fairly limited language, and most of its usage in CPython falls under a small set of syntax rules. Getting to the point where you understand the code is a much smaller step than being able to write C effectively. This tutorial is aimed at the first goal but not the second.
In this tutorial, you’ll learn:
- What the C preprocessor is and what role it plays in building C programs
- How you can use preprocessor directives to manipulate source files
- How C syntax compares to Python syntax
- How to create loops, functions, strings, and other features in C
One of the first things that stands out as a big difference between Python and C is the C preprocessor. You’ll look at that first.
Note: This tutorial is adapted from the appendix, “Introduction to C for Python Programmers,” in CPython Internals: Your Guide to the Python Interpreter.
Free Download:Get a sample chapter from CPython Internals: Your Guide to the Python 3 Interpreter showing you how to unlock the inner workings of the Python language, compile the Python interpreter from source code, and participate in the development of CPython.
The C Preprocessor
The preprocessor, as the name suggests, is run on your source files before the compiler runs. It has very limited abilities, but you can use them to great advantage in building C programs.
The preprocessor produces a new file, which is what the compiler will actually process. All the commands to the preprocessor start at the beginning of a line, with a #
symbol as the first non-whitespace character.
The main purpose of the preprocessor is to do text substitution in the source file, but it will also do some basic conditional code with #if
or similar statements.
You’ll start with the most frequent preprocessor directive: #include
.
#include
#include
is used to pull the contents of one file into the current source file. There’s nothing sophisticated about #include
. It reads a file from the file system, runs the preprocessor on that file, and puts the results into the output file. This is done recursively for each #include
directive.
For example, if you look at CPython’s Modules/_multiprocessing/semaphore.c
file, then near the top you’ll see the following line:
#include"multiprocessing.h"
This tells the preprocessor to pull in the entire contents of multiprocessing.h
and put them into the output file at this position.
You’ll notice two different forms for the #include
statement. One of them uses quotes (""
) to specify the name of the include file, and the other uses angle brackets (<>
). The difference comes from which paths are searched when looking for the file on the file system.
If you use <>
for the filename, then the preprocessor will look only at system include files. Using quotes around the filename instead will force the preprocessor to look in the local directory first and then fall back to the system directories.
#define
#define
allows you to do simple text substitution and also plays into the #if
directives you’ll see below.
At its most basic, #define
lets you define a new symbol that gets replaced with a text string in the preprocessor output.
Continuing in semphore.c
, you’ll find this line:
#define SEM_FAILED NULL
This tells the preprocessor to replace every instance of SEM_FAILED
below this point with the literal string NULL
before the code is sent to the compiler.
Read the full article at https://realpython.com/c-for-python-programmers/ »
[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]