Preprocessor Directives

This is a discussion on Preprocessor Directives within the C++ Programming forums, part of the General Programming Boards category; Hi, I'm trying to understand preprocessor directives a little bit better. But first, I have some questions I would like ...

Preprocessor Directives

Hi, I'm trying to understand preprocessor directives a little bit better. But first, I have some questions I would like sorted which I think are causing my failure to understand what Preprocessor Directives are...

The first question that I have is:

1.) if we are creating a program, why can there be more than one .cpp file attached to it? Aren't we writing code in one .cpp file in and around the 'main' function?

2.) ok so we have more than one .cpp file in our program (or in some we have just the one e.g. hello world) but essentially, when we run compile, it turns our C++ high level language code into machine code and spits out a .o or .obj file or something of the sort. How can we execute these .obj files? If we can't why not?

3.) Finally, we have the linking/linker whatever it is process. This process does what exactly? Haven't we already created the machine code during the compilation? Yes the name link suggests that we take the multiple .o/.obj files and morph them into 1 continuous file but I'm a little confused as why a .exe is what gets EXECTUTED by the processor whilst .obj and .o don't.

4.) It's said that C++ is quite a limited language in its raw form? How can it be so? Aren't libraries that we declare as Preprocessor Directives written in C++? OR is a library essentially a bunch of functions (which I know they are) which are written in the very basic raw C++ form which then you are then able to reuse i.e. not have to create from scratch every time you need to use one? So essentially a library is the first 'version' of object oriented code? Is another reason for using libraries in order to conserve space?

Finally 5.) When we link the .o/.obj files and create the .exe file, what actually happens? I'm guessing a program which does the linking process (either within an IDE or a 3rd party one) simply takes individual .o/.obj files and sticks them together one after the other? Or is this more conceptually what happens? So when it comes to INCLUDING various libraries or stating Preprocessor Directives, what ends up happening is that the linker essentially seeks the files where the library is stored, then copies the C++ code, compiles it into a .o/.obj form, then sticks it into ... where? Which .obj/.o file? The way I see it, all it's doing in this stage is essentially creating a machine code version of a function which one would write source code for and sticks it in some portion of some file which as I said, I'm not entirely sure where so that when the computer gets to a particular instruction, it knows exactly what to do.

Hence the space saving is occuring because this way, rather than having to copy every single conceivable function into the .obj/.o/.exe file so that if some function is called, the processor knows what to do, we only INCLUDE what is needed by the program? So essentially, #include is simply an instruction which the ?complier? or the ?linker? sees and then searches the libraries in some folder, finds the library and then copy pastes the functions within that library into our main.cpp file?

1.) if we are creating a program, why can there be more than one .cpp file attached to it? Aren't we writing code in one .cpp file in and around the 'main' function?

That only works for small programs. Yes, it is technically possible with larger programs, but humans have trouble looking at all the details contained in more than a couple of thousand lines of code and understanding what the whole program does.

Humans work by breaking big problems into littler problems that can be more easily tackled. In software development, that means breaking large systems into smaller parts, getting each of the parts working, and then combining the parts into a whole. Organising that process is facilitated by breaking code across multiple source files.

Originally Posted by Atomic_Sheep

2.) ok so we have more than one .cpp file in our program (or in some we have just the one e.g. hello world) but essentially, when we run compile, it turns our C++ high level language code into machine code and spits out a .o or .obj file or something of the sort. How can we execute these .obj files? If we can't why not?

Object files are an intermediate format. They represent pieces of software, but the individual pieces do not generally work in isolation: multiple pieces need to be stitched together, so they work together as a whole.

A function to (say) output a string can't do much unless it is invoked by other code which supplies a string.

Object files, because they represent a piece of software rather than a complete system, are not able to be executed. It therefore makes sense that object files have a different format from executable files (albeit the two formats are usually related). There is no value in trying to execute something that cannot be executed.

Originally Posted by Atomic_Sheep

3.) Finally, we have the linking/linker whatever it is process. This process does what exactly? Haven't we already created the machine code during the compilation? Yes the name link suggests that we take the multiple .o/.obj files and morph them into 1 continuous file but I'm a little confused as why a .exe is what gets EXECTUTED by the processor whilst .obj and .o don't.

The linker is the program that looks at the individual object files, identifies what other pieces they need, and stitches them together. For example, if code in one object file calls a function, and that function is implemented in another object file, the linker does the work to ensure that there there is an association between the code that calls a function and the entry point of the actual function.

The linker will also complain bitterly if it cannot do that (for example, one object file needs a function that is not implemented in any of the other object files or libraries being linked together). When the linker cannot do its job, it does not create an executable.

Originally Posted by Atomic_Sheep

4.) It's said that C++ is quite a limited language in its raw form? How can it be so? Aren't libraries that we declare as Preprocessor Directives written in C++? OR is a library essentially a bunch of functions (which I know they are) which are written in the very basic raw C++ form which then you are then able to reuse i.e. not have to create from scratch every time you need to use one? So essentially a library is the first 'version' of object oriented code? Is another reason for using libraries in order to conserve space?

All programming languages are "limited" in their raw form. All compilers or interpreters rely on some infrastructure (eg other programs or the host system) to produce the intended result.

The whole point of libraries is to allow code to be reused in multiple programs. If you want to output a string in two different programs, you would not be particularly productive if you were required to write a brand-new function from scratch to perform that output.

The design of any language involves a decision about what is done in libraries (which are essentially a file format that bundles multiple object files so they can be accessed by the linker) versus what is built into the language. The trade-off is usually one of compiler complexity versus flexibility of the language: it is significantly harder to modify a non-trivial compiler to introduce a new language feature than it is to add or update a function in a library, but (once the compiler is modified) it is easier for a programmer to use a language feature than it is to use library functions.

Generally doing things in the "language" rather than in the "library" works best for simple languages: it is easier to modify a compiler for a simple language than it is to modify a compiler for a complex language. The problem is that "simple" languages tend to be specialised. All well and good if you are doing something that language is designed to support. But you are in trouble if you are trying to do something that language does not allow.

C++ is a large language, because it is general-purpose. Doing things in the standard C++ library allows C++ to be more powerful (and general-purpose) without making the base language even bigger and more complex than it already is: it is often easier to add a new feature by extending the library than it is to extend the compiler.

Originally Posted by Atomic_Sheep

Finally 5.) When we link the .o/.obj files and create the .exe file, what actually happens? I'm guessing a program which does the linking process (either within an IDE or a 3rd party one) simply takes individual .o/.obj files and sticks them together one after the other? Or is this more conceptually what happens?

I've already addressed this above.

Originally Posted by Atomic_Sheep

So when it comes to INCLUDING various libraries or stating Preprocessor Directives, what ends up happening is that the linker essentially seeks the files where the library is stored, then copies the C++ code, compiles it into a .o/.obj form, then sticks it into ... where?

In C++, the preprocessor takes in source code, and does text substitution. The input to the preprocessor is code. The output to the preprocessor is also source code, but all preprocessor directives have been replaced by their textual equivalent (macros have been expanded, etc).

When including a header file, for example, the text in the header file is substituted for the #include directive (a straight text substitution).

The preprocessed source code is fed to another phase of the compiler, which converts (preprocessed) source code into object files (and depending on the compiler, possibly to other file types such as assembler output).

If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.