g++ main.cpp file1.cpp file2.cpp -o main
Why this sucks:
Solution: makefile!
make
all: data.o io.o main.o
gcc data.o io.o main.o -o myexecutable
data.o: data.c data.h
gcc -c data.c
io.o: io.c io.h
gcc -c io.c
main.o: main.c data.h io.h common.h
gcc -c main.c
clean:
rm *.o myexecutable
Each line has a target, dependencies, and an action or command.
make
is called, the make build all
is ran. You can type make data.o
instead to run the process for data.o
.This is what macros look like (note that there is no checking of validity until the commands are run):
OBJECTS = hello.o classname.o
CPPFLAGS = -c -Wall -Wextra -Wvla -pedantic -O3
To start, type gdb <exe_name>
.
<assert>
libraryassert
that something is true, and if it is not true then the code triggers a breakpoint.class PowerRaiser {
public:
PowerRaiser( unsigned int _base) : base(_base) {}
unsigned int getBase() {
return base};
}
class PowerRaiserTest{
public:
runTestGetBase() {
PowerRaiser p(10);
assert(p.getBase() == 10);
}
runTestRaise() {
PowerRaiser p(3);
assert(1 == p.raise(0));
assert(3 == p.raise(1));
}
testAll() {
testGetBase();
testGetPower();
}
}
Class structure:
cin
: read from stdin
cout
: write to stdout
cerr
: write to stderr
ifstream
: open files with read permission
ofstream
: open files with write permission
fstream
: open files with read and write permission
./path281 < input.txt > output.txt
Instead of reading from cin
, path281 executable will now read from input.txt
and instead of writing to cout
, it will write to output.txt
.
int main() {
while (cin.get() != -1) {
cin.unget();
char c = cin.get();
cout << c;
}
}
Or, faster:
int main() {
char c;
while ((c = cin.get()) != 1) {
cout << c;
}
}
int main() {
string s;
while(getline(cin, s)) {
cout << s << endl;
}
}
int main() {
for(int i = 0; i < 100; i++) {
cout << i << endl;
}
}
This is inefficient, because you have to flush to the buffer every time. When you use a newline instead, then it is universally faster because the system determines when to flush the buffer.
int main() {
for(int i = 0; i < 100; i++) {
cout << i << '\n';
}
}
#include <sstream>
int main() {
ostringstream ss;
for(int i = 0; i < 100; i++) {
ss << i << '\n';
}
cout << ss.str();
}
Motivation: simplifies command line parsing
./exec -a mergesort -V 1.0
In argv
, all flags and values are treated the same way.
Instead of coding a way to parse the command line arguments every time, GNU provided a way to do this in a standard way.
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv) {
int aflag = 0; int bflag = 0;
char *cvalue = nullptr;
int index, c;
while ((c = getopt(argc, argv, "abc:")) != -1) {
switch (c) {
case 'a':
// do something
break;
case 'b':
// do something else
break;
case 'c':
// do something with the value of c
// optarg is the value of the argument after
// the -c flag is used.
string foo = optarg;
break;
}
}
}
"abc:"
means that an argument is required for c
.
optarg
: global external variable in <stdio.h>
, representing the value for the argument, if the variable requires an argument.
./exec -a -b -c foo
Or, alternatively:
./exec -a -c foo -b
If you want two flags to have arguments, use "a:b:c:"
. This means that you could call the executable like so:
./exec -a hello -b goodbye -c mergesort
The order of the arguments does not matter. This is only if the flag only has one argument. However, there is a way so that you can specify more than one argument for a flag.
Use another external variable in <stdio.h>
, the variable optind
.
// First non-optional argument
string arg1 = argv[optind];
// Second non-optional argument
string arg2 = argv[optind + 1];
When you call an executable with non-optional arguments, the non-optional arguments are automatically moved to the end of the flag list, and then you can access them by indexing them at the optind + i
position.
Some options can be verbose:
./exec -h
./exec --help
You have to structure things a bit differently for a verbose option:
struct option {
const char * name;
int has_arg;
int *flag; // set to null all the time
int *value; // takes the first letter of name and converts it to ascii.
}