C++
About C++
C++ (pronounced cee plus plus) is a general purpose programming language developed by Bjarne Stroustrup starting in 1979 at Bell Labs. It is immensely popular, particularly for applications that require speed and/or access to some low-level features. It is considered to be an intermediate level language, as it encapsulates both high and low level language features. Uses include Vst and VCVRack plugin development.
C is what we call a compiled language. This is because programs, written with C code in a text file, are generated by a package of programs called the compiler. These programs transform the text code into binary codes that are understood by the machine and the operating system. The process of compilation/program building is discussed below. Interpreted languages, such as Python, are generally higher-level languages that are dependent on an interpreter program, which translates the text code into machine actions directly. Their advantage is that the result of the programming can be seen immediately. On the other hand, generally speaking, the overhead of interpreting the code can make these languages very inefficient for intensive tasks (such as calculating the output of a synthesis routine, in the case of a music system).
Overview[edit]
Compiling[edit]
After opening your console/terminal window, you can invoke the compiler program can be called by the simple command
cc mysource.c
where cc is the C compiler and mysource.c is the name of your source file. (gcc is a very widespread compiler, if you are using it, just change the command for gcc.) The output of this command will be a binary executable file called a.out, which you can rename (using mv) if you want. This file will sit in the directory you are working on.
For more practical uses, you can output the binary executable to a different file, using
‘-o . . . ’ (just as in Csound ‘-o’ means ‘‘output to’’): cc -o myprogr mysource.c
On Windows machines your program filename will have the extension .exe. On other systems no extensions are used.
Source Files[edit]
Source files are text (ASCII) files containing the source code written in C, which will be used to build the program. There can be just one or many of these needed to build a program.
Header Files[edit]
Header files (usually with extension .h) are files with definitions and parts of code which are included in (i.e. they will be copied to) the source files. The compiling process will use the code in these header files in the compilation process.
Libraries[edit]
C is a very lean language. It has a number of built-in definitions, rules, etc.; the rest is done by elements (functions, data definitions, etc.) existing in libraries. These are pre-compiled (i.e. they are already in binary) and are added to the executable at the last phase of the build of the program. In this phase, called linking, references to libraries are linked to the actual binary code. There are libraries for virtually anything you want to do in C: math, sorting, comparing things, controlling processes, playing audio and MIDI, etc. When using different libraries, you will have to inform the compiler which one(s) you are using. This can be done with the relevant command-line options. (For more details, see appendix A.)
The Build Process[edit]
The ‘‘program build’’ has three main phases:
1. Pre-processing. This expands all include header files (by copying them into the source code) and other preprocessor statements (which usually start with the character #) found in the source file(s).
2. Compiling. This reads the source code and transforms it into binary code for the machine you are targeting (i.e. the machine for which you’re building the program).
3. Linking. This links all references to binary code that is not in the source code (i.e. in libra- ries), as well as putting together all source binaries (if there are multiple source files). These three stages can be done in one go, or if you like, separately. Usually, when building large pieces of software it is common to do steps one and two at one time and then leave the linkage process for later. The source files are compiled into binary files called object files (extension .o), which can later be combined (linked) to make the program. This is usually the case when there are many source files in the project. This procedure enables the programmer to compile the different source files only when they have been modified, saving time and resources. Utilities such as make or scons can be used to maintain a build project and will automatically call the compiler and the linker to build from sources that have been updated.
Program Format and Layout[edit]
A C executable program requires that at least one function be present in it. This is what we call the entry point of the program: where it starts executing and also providing the exit point, i.e. when the function ends, the program also finishes. By default this function is called main(), but this can be changed by a compiler flag (although we will not normally do it). This function can take two forms:
int main( );
and
int main(int argc, char* argv);
The first form does not take any arguments and, being the simplest, is the one we will use first. Both forms are supposed to return (i.e. ‘‘answer with’’) an integer number, which is passed as a code to the operating system (generally 0 means OK). The second form will be discussed later in section 0.15. In addition to main(), the program can also have other func- tions, although they are not absolutely required.
Functions[edit]
In C, functions are also known as subroutines or procedures. A function is simply a block of code grouped together and given a name. This block of code can then be invoked just by using its name in a statement. For instance a function can be declared to print a message and exit:
void message() { printf("This is my message\n"); }
Now that it is defined, you can use it:
int main() { message(); return 0; }
As the function does not return anything, it is defined with the return type void, meaning ‘‘nothing.’’ It also does not take any arguments, so there is nothing inside the parentheses. Note that any variables declared inside a function (a code block) are only valid and seen inside that block. These variables are local and they will disappear when function exits. In order to pass in values to local variables and to get the answers out of functions, we will use arguments (parameters) and return values.
Arguments and Return Types[edit]
Passing values to a function is done via its arguments. These are defined within the paren- theses, each one with its type and separated by commas. Arguments declared like this also behave as local variables for the function. In order to pass the answer (if any) that the func- tion provides, we use the keyword return:
int sum(int a, int b) { int result; result=a + b; return result; }
This defines a function (called sum) with two parameters, a and b, both integers, returning an integer, and can be used as
a = sum(2,2);
This is a call to the sum function with a set to 2 and b set to 2, and so result is set to 4. You can also initialize parameters to the results of expressions such as
a = sum(x+y,z*w);
This will set a to the result of x+y and b to z*w. The values of the arguments are copied into them as the function is called. C passes copies of variables as arguments, not the variables themselves. In summary, a function has the general form
type FunctionName(arguments) { statements }
Notic e that the function will always exit when it reaches a return statement. The rest of the code beyond it will be skipped. The return statement can return a value or (in the case of void return types) nothing at all.
Prototypes[edit]
Before a function is used, the compiler must be given the return type and any arguments for it. Thus, in order to use it, we will first have to declare it. We need not completely define (implement) it before it is used; we need only declare it. In that case, we can provide the function prototype: its type, name, and arguments. For instance,
int sum(int, int);
is the prototype for the sum function defined above. The function definition can then go elsewhere in the source code—after main(), or even in a different source file. By default, if a function is not declared before use, it is assumed to be an int function—which is not always correct.
Pointers[edit]
As we mentioned earlier, a variable is a memory slot that has been given a name. For exam- ple, int x; is an area of memory that has been given the name x, and x=10; stores the data constant 10 in memory slot x. The computer accesses its own memory by using a memory map with each location of memory uniquely defined by a number called an address. A pointer is a variable that holds this location of memory, the address of a variable. We declare it just like any other variable, but we use an asterisk to mark it. For example,
int *pa;
is a pointer to an integer. To use a pointer, we will employ two special operators: & and *. We have already seen that the & operator returns the address of a variable. For example, int *pa, a; declares pa, a pointer to int, and an int, and the instruction
pa=&a;
stores the address of a in pa. We say that pa is pointing at a.
The operator ‘*’ is the indirection operator. A ‘*’ in front of a pointer variable gives the value stored in the variable pointed at. That is, pa stores the address of a variable, and *pa is the value stored in that variable.
a = 10; b = *pa; /* b is now also 10 */ *pa = 12; /* a is now 12 */</nowiki>
In summary:
- A pointer is declared by a ‘*’ in front of its name.
- The address of a variable is given by a ‘&’ in front of its name.
- To obtain or store the value of a variable (pointed at), use ‘*’ in front of a pointer.
Pointers and Arrays[edit]
Pointers and arrays are closely connected. If you declare an array as int a[10]; you are also declaring a pointer a to the first element in the array. Here, a is equivalent to &a[0]. The only difference between a and a pointer variable is that the array name is a constant pointer and cannot be used as a variable. In this sense, a[i] and *(a+i) are equivalent, which makes possible what is called pointer arithmetic, adding integers to pointers to step through a memory block. The compiler will know how many bytes to move forward when you add a certain number of memory slots to it. If it is an int, it will jump four bytes (system-dependent of course) each step, if it is a double, then it will jump eight bytes. This is one of the reasons why the compiler needs to know the type of a variable when you declare it.
Finally, when you pass an entire array to a function then by default a pointer is passed. This allows you to write functions that process entire arrays without having to pass every single value stored in the array, just a pointer to the first element: int randarray(int *pa, int n)
{ int i; for (i=0; i < n; i++) { *pa = rand()%n + 1; pa++; } }
The loop can in fact be reduced to
for(i=0; i<n; i++) *(pa+i)=rand()%n+1;
31 An Overview of the C Language or
for(i=0; i<n; i++) pa[i]=rand()%n+1;
If you define pa as a pointer, you can use array indexing notation with it as well as pointer arithmetic.
Strings, Arrays, and Pointers[edit]
We now see that a string is just a character array with the end of the valid data marked by an ASCII null character ‘\0’. Manipulation of strings is based on pointers and special string functions. For example, the strlen(str) function returns the number of characters in the string str. It counts the number of characters up to the first null in the character array, so it is important to use a null-terminated string. We need a function to copy strings, because simple assignment between string variables does not work. For example,
char a[l0],b[10]; b = a;
does not copy characters. It just makes pointer b set point to the same set of characters that a points to, but a second copy of the string is not created (in fact, this code will not even com- pile). What we need is strcopy(a,b), which copies every character in a into the array b up to the first null character. Similarly, strcat(a,b) adds the characters in b to the end of the string stored in a, and strcmp(a,b) compares the two strings, character by character, and returns 0 if the results are equal. Notice that, to assign a character array to a string, you cannot use
a = "hello";
because a is a pointer and "hello" is a string constant. However, you can use
strcopy(a,"hello");
because a string constant is passed in exactly the same way as a string variable, i.e. as a pointer. And remember, a string can always be initialized. For example:
char a[6]="hello";
As with all C parameters, structures are passed by value; thus, if you want to allow a function to alter a parameter you have to remember to pass a pointer to a struct.
Command-Line Arguments[edit]
Now let us look at how to get arguments off a command line. This uses the second form of main() shown at the beginning of the chapter. Command-line arguments are passed to a program through two arguments to the main() function. The parameters, are called argc and argv, are seen in the following main prototype:
int main(int argc, char **argv)
The argc parameter holds the number of arguments on the command-line and is an integer. It will always be at least one because the name of the program is the first argument. The argv parameter is an array of string pointers. All command-line arguments are passed to main() as strings. For example:
#include <stdio.h> int main(int argc, char *argv[]) { int i; for (i=1; i<argc; i++) printf("%s", argv[i]); return 0; }
This program will print out all of its arguments, starting with the program name
IDEs & Tools[edit]
Cross Platform[edit]
GCC[edit]
The GNU Compiler Collection includes front ends for C, C++, Objective-C, Fortran, Ada, Go, and D, as well as libraries for these languages (libstdc++,...). GCC was originally written as the compiler for the GNU operating system. The GNU system was developed to be 100% free software, free in the sense that it respects the user's freedom.
Make[edit]
In software development, Make is a build automation tool that automatically builds executable programs and libraries from source code by reading files called Makefiles which specify how to derive the target program. Though integrated development environments and language-specific compiler features can also be used to manage a build process, Make remains widely used, especially in Unix and Unix-like operating systems. Besides building programs, Make can be used to manage any project where some files must be updated automatically from others whenever the others change.
Cmake - Cross Platform compiler-independant builder[edit]
Make is an open-source, cross-platform family of tools designed to build, test and package software. CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and generate native makefiles and workspaces that can be used in the compiler environment of your choice. Allows for the configuration of multiple build environments across different platforms, especially useful for teams that use different OS
Windows[edit]
Visual Code[edit]
Plugin Based IDE Works well with MingGW64 & GCC. Similar to PhpStorm and other intellisense based IDEs
MSYS2 - Windows Package Manager[edit]
MSYS2 is a collection of tools and libraries providing you with an easy-to-use environment for building, installing and running native Windows software.
It consists of a command line terminal called mintty, bash, version control systems like git and subversion, tools like tar and awk and even build systems like autotools, all based on a modified version of Cygwin. Despite some of these central parts being based on Cygwin, the main focus of MSYS2 is to provide a build environment for native Windows software and the Cygwin-using parts are kept at a minimum. MSYS2 provides up-to-date native builds for GCC, mingw-w64, CPython, CMake, Meson, OpenSSL, FFmpeg, Rust, Ruby, just to name a few.
To provide easy installation of packages and a way to keep them updated it features a package management system called Pacman, which should be familiar to Arch Linux users. It brings many powerful features such as dependency resolution and simple complete system upgrades, as well as straight-forward and reproducible package building. Our package repository contains more than 2000 pre-built packages ready to install.
For more details see 'What is MSYS2?' which also compares MSYS2 to other software distributions and development environments like Cygwin, WSL, Chocolatey, Scoop, ... and 'Who Is Using MSYS2?' to see which projects are using MSYS2 and what for.
Mingw-w64 - GCC runtime environment[edit]
The mingw-w64 project is a complete runtime environment for gcc to support binaries native to Windows 64-bit and 32-bit operating systems. Mingw-w64 is an advancement of the original mingw.org project, created to support the GCC compiler on Windows systems. It has forked it in 2007 in order to provide support for 64 bits and new APIs. It has since then gained widespread use and distribution.
Code Blocks(open source)[edit]
Visual Studio (Closed Source)[edit]
MAC[edit]
Linux[edit]
Hardware[edit]
Books[edit]
The Audio Programming Book
Audio Tutorials[edit]
- Exercism.org Massive Computer Language Tutorial System
- VCVRack
- Vult
- Pulse Audio
Audio Frameworks & Libraries Supported by EMC23[edit]
PortAudio is a free, cross-platform, open-source, audio I/O library. It lets you write audio programs in 'C' or C++ that will compile and run on many platforms including Windows, Macintosh OS X, and Unix (OSS/ALSA). It is intended to promote the exchange of audio software between developers on different platforms. It provides a very simple API for recording and/or playing sound using a simple callback function.
RtAudio is a set of C++ classes that provide a common API (Application Programming Interface) for realtime audio input/output across Linux, Macintosh OS-X and Windows operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following objectives:
- object-oriented C++ design
- simple, common API across all supported platforms
- only one source and one header file for easy inclusion in programming projects
- allow simultaneous multi-api support
- support dynamic connection of devices
- provide extensive audio device parameter control
- allow audio device capability probing
- automatic internal conversion for data format, channel number compensation, (de)interleaving, and byte-swapping
- RtAudio incorporates the concept of audio streams, which represent audio output (playback) and/or input (recording). Available audio devices and their capabilities can be enumerated and then specified when opening a stream. Where applicable, multiple API support can be compiled and a particular API specified when creating an RtAudio instance. See the API Notes section for information specific to each of the supported audio APIs.
JUCE has hundreds of classes covering a vast range of tasks from high-level user-interface handling right down to low-level collections, networking, strings, etc. Supported platforms are OSX, Windows, Linux, iOS and Android, and the Introjucer project management tool makes it a breeze to create and maintain cross-platform projects.