I'm not sure how to ask this but here it goes.
I am building a C++ application, in this case I'm building it in Code::Blocks with a MingW compiler. I want to incorporate/utilize/whatever, SQLite into my applicaiton by including (#include) the sqlite C code header file sqlite3.h in my project file. This question is not necessarily about SQLite but it's about using the sqlite3 source code file written in the C Programming Language in my C++ program (statically linking) not DLL. If the sqlite3.c (source code file) is written in c, how can I compile my application written in C++ (I'm using a C++ compiler).

Here's what I have.
1 - My project file written in C++.
2 - I have included the header file for SQlite written in C.
3 - I have placed the C source code file in my Project File directory. (maybe thats not correct but thats what Iv'e done.)

If the C source code file is written in C and I can't compile it in a C++ compiler (so I'm told) then how do I compile a SQlite cource code file in any compiler (a C compiler) if it is not called by a Main() function which in this case is written in C++?

As I said, this is not a question about SQlite but it is a conceptual question to understand the process of statically linking a C source code file into a C++ project.

Any help with this would be greatly appreciated.

Thanks

Recommended Answers

All 6 Replies

If the C source code file is written in C and I can't compile it in a C++ compiler (so I'm told)

They told you wrong.

There is no problem at all mixing C and C++ files in the same program, I've done it several times. It's all in the file extension, the compiler sees a *.c and knows that it has to compile it as C code, and if it sees *.cpp extension the compiler compiles it as c++ code. No other special things have to be done to the source files or the compiler flags. sqlite.h already contains the preprocessor flags needed to tell the compiler that all the functions are written in C instead of C++ so that the header file can be included in c++ programs.

Some C header files are not C++ safe. If you get compiler and/or linker errors when you try to do so, then "guard" the #include <someCheader.h> directives with extern "C" {...}. Example:

#ifndef MYCPPHEADER_H
#define MYCPPHEADER_H
// My C++ header file
extern "C" {
#include <someCheader.h>
}
.
.
.
#endif // MYCPPHEADER_H

Thanks allot for that. It's the first time I've had a clear explanation on this. Part of the reason for the confusion is a section in the book: 'Using SQLite', Orielly book (August 2010) which says the below. Is this just wrong or are they being cautious about mixing C and C++?

Just remember that the core SQLite library is C, not C++, and cannot be compiled with
most C++ compilers. Even if you choose to wrap the SQLite API in a C++ class-based
interface, you’ll still need to compile the core SQLite library with a C compiler.

Secondly, if you can easily mix C and C++ code like that then why do we need all those C++ wrappers out there for wrappign C code for SQLite. Is that more about the style of the interface (API)?

Thanks

Here is an example I wrote in 2009 that uses Sqlite in a c++ program. I don't know about the c++ wrappers you mentioned because I have not used any of them.

Is this just wrong or are they being cautious about mixing C and C++?

No, it is correct. When you are using a compiler like GCC (within MinGW distribution), this is actually the GNU Compiler Collection which includes both a C compiler and a C++ compiler (at least, but often a few others like Fortran, Ada, and possibly Objective-C and Java compilers). What Ancient Dragon explained about extensions *.c vs. *.cpp is that CodeBlocks will invoke the gcc.exe program to compile all the source code, and that program is made to check the file extension and compile the code accordingly with the appropriate compiler (i.e., its C or C++ compiler). GCC uses the same backend for all its compilers and it uses one linker for all linking tasks, so, once individual source files were compiled, it doesn't make a difference from which original language they were compiled from, they all just link together (as long as they have the appropriate extern "C" wrapping in the headers in between C and C++ code). So, SQLite is correct in saying you can't compile their code with a C++ compiler, only with a C compiler, but that is already what is happening under-the-hood when you add the C code to your project.

The more pedantic way to do this is to take all the C code from that external library and compile it into a static or shared library, and then link that static library to your compiled C++ code. It is generally considered somewhat bad style to put together many source files for different libraries into a single "project", but it works as long as the compiler in question can do the dispatching to the appropriate compiler for each source file (as does GCC and most other compiler suites).

Secondly, if you can easily mix C and C++ code like that then why do we need all those C++ wrappers out there for wrappign C code for SQLite. Is that more about the style of the interface (API)?

Yes, it is mostly about style. The more you program in C++ the more you develop a certain distaste for C-style code (opaque-pointers, struct + free functions instead of classes, lots of type unsafe code, etc.). Then, there are many common and recommended practices in C++, such as resource encapsulation (or RAII), which are generally beneficial to the robustness of the code and also simplifies the source code (e.g., being able to use the compiler-defaulted destructor, copy-assignment, and copy-constructor). If you want to abide by those coding practices, which are often incompatible with C-style coding (due to lack of classes, references or strong type safety), then you need to wrap the C-style code (that interfaces the external library) very early on such that your code only is not "infected" by the C-style code too deeply.

And then, there are technical reasons, for instance, inter-operability with standard C++ libraries, like wrapping a networking library into a set of classes derived from C++ iostream base classes such that anything that can already be printed to the console or a file (i.e., for which you have overloaded the iostream << and >> operators) can also be sent over a network connection. Or making an external C library look like a STL container, and so on. Another technical reason is for a technique called the "compilation firewall" (or "PImpl idiom", or "Cheshire Cat") whose aim is to isolate the external dependency completely from your project's code, which is often a good idea when the external library has a C interface or is of doubious quality of implementation. To do that, you already need to implement a wrapper that hides away the external dependency in a separate cpp file while exposing functions and classes in its header which show no traces of the external dependency, so, you might as well write that wrapper in good C++ style.

Finally, C is the lingua franca of external library interfaces (this is mostly for technical reasons, mostly, and partly for legacy reasons). Often, the original source code of the library will not be in C, often in C++. So, in this case, since, as the library developer, you already have to create wrapping code to make the C++ source code look like C source code, it is not so much trouble to also make the wrapping code that does the opposite, for those who will want to use your library in a C++ project. And there are technical reasons why you can't just skip the C interface, and go with C++ all the way, so, you very often see libraries that have a C API and a C++ wrapper available for it.

commented: Thanks for the effort. Great Answer. +2

Thanks Mike.. Thats a great explanation. I understand now.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.