Introduction to Programming and C++#
C++ is
A high level language
A powerful, battle tested language (old), with new standards every 3 years.
A multiparadigm language (we will learn only a subset)
A compiled language (using compilers like
g++
oricc
)Highly performant, used vastly on scientific and many other applications: amazon.com, intel, IBM, facebook, Google, Microsoft, Apple, Adobe, …
Games written in c++: Assasins creed, Call of Duty, Mass Effect, World of Warcraft, Starcraft, Halo, Among Us, …
The main idea at the end of this course is to be able to program something like https://www.youtube.com/watch?v=lS_qeBy3aQI, where more complex systems are available https://flyover.github.io/box2d.ts/testbed/
C++ allows you to really exploit your computational resources: https://computers-are-fast.github.io/
Also, if you want to know more about a computer, please check https://www.youtube.com/watch?v=d86ws7mQYIg
Here is an outline
Typical basic workflow#
%load_ext nb_js_diagrammers
%%mermaid_magic -h 500
graph TD;
A[Understand the problem] --> B[Edit the code: vscode, emacs, vim, ...]
B --> C[Compile your code: g++ filename.cpp]
C -- Yes --> D[Execute the executable: ./a.out]
C -- No --> B
D -- Yes --> E[Analyze results: Plot, fit, etc. Maybe use python]
D -- No --> B
E -- No, or improvement --> B
E -- More thinking needed --> A
Understand the problem. Think about the tasks you need as a high level version.
Edit the code: vscode, emacs, vim, …
Compile your code:
g++ filename.cpp
. In case of errors, return to step 1.Execute the executable:
./a.out
. In case of errors, return to step 1.Analyze results: Plot, fit, etc. Maybe use python. In case of errors, return to step 1
The following shows the workflow for a helloworld program.
Step 0: Think
We want a program that prints the message “Hello world” to the standard output (the screen, normally). So we need a standard header like iostream
, and use std::cout
. Therefore our general program flow would be
library to print to the screen: include iostream
in the main function
use cout or print or println or printf to write "Hellow world"
Step 1: Edit We will edit the code now. Please use an editor and write the following code
// This prints a comment
#include <iostream>
int main(void)
{
std::cout << "Hello world\n";
return 0;
}
Step 2: Compile
Now we will compile with the compiler g++
(there are a lot more). In a terminal, in the same directory where the fie was saved, just run
g++ helloworld.cpp
You have terminals available in a local or remote linux installation, in vscode in a code space, in binder, but not in google collab. There you need to either pay to have a terminal (is not that expensive), or just run a cell prepending !
as follows
!g++ helloworld.cpp
This produces the executable a.out
(you can change the name using the compilation flag -o name.x
), as
g++ helloworld.cpp -o hello.x
You can check the contents of the current dir with
ls
(remeber to prepend a !
if you are using collab)
Step 3: Execute To execute, we need to specify the path to the executable. We are going to use the symbol ‘./’, which means the current directory
./hello.x
(or ./a.out
)
Congratulation! Now you are a c++ developer … not so fast!
Understanding helloworld#
There are a lot of things under the hood for the simple helloworld program.
Pre-processor#
The line
#include <iostream>
Tells the pre-processor to include the standard library iostream
, which is the one in cahrge of (i)npunt and (o)utput of (stream)s. It also gives you std::cin
to read from the standard input, std::cerr
and std::clog
for the standard error, and so on. There are many standard headers, and you should get familiar and use them extensively. Please see cppreference .
The pre-processor allows conditional compilation, activates possible parallelism with openmp and does many more things, but for now we will keep it usage like that. Actually, it is in the path to be eliminated in favor of modules.
Do not use .h
headers. Those come from C , are not using the std
namespace, and are a bad practice.
The main function#
Good programming is based on splitting a daunting task into several smaller tasks that are isolated from each other and perform one thing well. Therefore, the concept of a function is of paramount importance. In c++, a function has a name, a set of arguments (parameters that it receives, like the domain, although the parameter number and type can be any), and a result type (a range) if it returns something. The typical function prototype is
return_type function_name(type1 par1, type2 par2);
As an example, the following is the declaration (how is called, what it receives and what it returns) for a that receives two integers and return their sum
int sum(int a, int b);
and this would be the implementation
int sum(int a, int b) {
return a+b;
}
For reasons that we will learn later, modularization is very important.
There is a very important function, called the main
function, which is mandatory per program (and only can be per executable) and is the one that talks to the operating system. Usually, it is expected that the main function calls other functions in the program. Some signatures of the main function are
int main(void)
{
...
}
which means that the executable does not receive any arguments, or
int main(int argc, char **argv)
{
...
}
which mean that the executable can receive arguments, like
./program.x 1.2 3
std::cout
to print#
The instruction std::cout
allows to print to the standard output. The \n
prints a new line. Warning: Do not use
using namespace std; // DO NOT DO THIS
it is a bad practice, frowned upon. You can use a linter or static analysis tool, like cpplint, to chech for advice and errors.
Return statement#
The return
statement allows to exit the function, returning something or nothing. It depends on your use case if you need it or not.
Practical exercise#
Now please write a program that reads your name, and then prints Hello, your-name-here
. Check if it is better to use std::cin
or std::getline
. Compile it and test it.
# Compilation
# Execution
Some useful tools#
As you learn more and your apps grow in complexity, you might need to use tools to easy the developer work so to focus on the analysis and results, while mantaining readability and good practices. Please also focus in this in learning linux, is the environment that scientist use. You can find many online resources, like http://www.ee.surrey.ac.uk/Teaching/Unix/ or https://swcarpentry.github.io/shell-novice/. For a general overview of what it means to be a modern c++ developer, see https://roadmap.sh/cpp
IDE#
An IDE is not just an editor but also gives you an environment with debuggers, refactoring, etc. You might use
Visual studio code . Very famous right now. Runs on electron. Can connect remotely, but cannot run in the terminal. A lot of metrics sent to servers.
VSCodium Free implementation, no telemetry. But not all plugins work.
Emacs doom or space emacs. Emacs distributions with many packages to make emacs a useful IDE.
Lapce A rust implementation which is very fast.
And much more: Sublime text, atom, Notepad++, Eclipse, Clion, Blocks , ..
Sanitizers#
When compiling, use sanitizers to allow for runtime error detections
g++ -fsanitize=address,undefined,leak filename.cpp -o ...
Debuggers#
A programmer spent 80% of the time debugging and fixing its code, and 20% programming. To track errors, it is useful to use something more advanced than printing messages (poor’s man debugger). You can use tools like:
The debuggers included on visual studio code, emacs or the IDE you selected (they basically use gdb under the hood)
Linters#
Sometimes you need tools that tell some possible errors in your code without actually running it. You can use
Formatting#
Formatting the code is key for readability of one self and others. You can use something like clang-format to format your ugly and unreadable code.
Compilation#
There are several compilers that you can use, like:
Amd compilers Sometimes it is useful to try several compilers to find possible bugs in the code.
There are also some online alternatives, useful to test code and small projects (see also the debugging section)
As your code grows in complexity (but even in the case of simple projects), the constant compilation, debugging, linting, etc could transform into a repetitive task that might be automatized. For simple projects you can use gnu make, using tutorials like https://makefiletutorial.com/ or https://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/ or http://swcarpentry.github.io/make-novice/. For more complex projects and multiplatform support, you might use cmake.
Package managers#
Besides the typical operating system package manager, you can also use tools like spack, meson, vcpkg, conan, …
Version control#
It is ALWAYS advisable to use version control. Please use git, so you will be able to rollback changes, create, merge and delete branches, activate continuous integration, and so on. You can also sync with remote repositories in portals like https://github.com/, or https://about.gitlab.com/why-gitlab/ . There are many tutorials, like https://swcarpentry.github.io/git-novice/ or https://learngitbranching.js.org/
Testing#
It is very important to write code that is testable, and to test constantly specially when introducing new changes To do so, you can use https://github.com/catchorg/Catch2, https://github.com/google/googletest , etc
Reproducible environments#
When you write a new program and want to distribute it, or run it on another machine, you must ensure that it runs as in the original development machine. To do so, the modern solution is to use containers. Learn how to use docker or Podman. This will be required for the final project.
Documentation#
Use comments, and better, use something like doxygen
Comments#
You can add comments, ignored by the compiler, using either
//
, for single line comments, orfor multiline comments.