Why Use G++ Instead of Gcc to Compile *.Cc Files

why use g++ instead of gcc to compile *.cc files?

It depends on what exactly you changed in the makefile. gcc / g++ is really just a front-end driver program which invokes the actual compiler and / or linker based on the options you give it.

If you invoke the compiler as gcc:

  • it will compile as C or C++ based on the file extension (.c, or .cc / .cpp);
  • it will link as C, i.e. it will not pull in C++ libraries unless you specifically add additional arguments to do so.

If you invoke the compiler as g++:

  • it will compile as C++ regardless of whether or not the file extension is .c or .cc / .cpp;
  • it will link as C++, i.e. automatically pull in the standard C++ libraries.

(see the relevant bit of the GCC documentation).


Here's a simple program which detects whether or not it has been compiled as C or C++.

(It makes use of the fact that a character constant has the size of an int in C, or a char in C++. sizeof(char) is 1 by definition; sizeof(int) will generally be larger - unless you're using an obscure platform with >= 16-bit bytes, which you're probably not.)

I've called it test.c and copied it as test.cc as well:

$ cat test.c
#include <stdio.h>

int main(void)
{
printf("I was compiled as %s!\n", sizeof('a') == 1 ? "C++" : "C");
return 0;
}
$ cp test.c test.cc
$

Compiling and linking test.c with gcc, and test.cc with g++, works as expected:

$ gcc -o test test.c
$ ./test
I was compiled as C!
$ g++ -o test test.cc
$ ./test
I was compiled as C++!
$

Compiling and linking test.cc with gcc doesn't work: it compiles the code as C++ because the file ends in .cc, but fails at the link stage:

$ gcc -o test test.cc
/tmp/ccyb1he5.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
collect2: ld returned 1 exit status
$

which we can prove by separately compiling with gcc, and linking with g++ (to pull in the right libraries):

$ gcc -c test.cc
$ g++ -o test test.o
$ ./test
I was compiled as C++!
$

...gcc has compiled the code as C++ rather than C, because it had a .cc file extension.

Whereas g++ does not compile .c files as plain C:

$ g++ -o test test.c 
$ ./test
I was compiled as C++!
$

Is it possible to use hash lines instead of every single cmdline argument passed to GCC?

I have trouble supplying each cmdline options everywhere.

Why? Are you using some build automation tool like GNU make? I believe you should use it, then it is just a matter to add a few appropriate lines in your Makefile (probably something like adding a line such as CXXFLAGS += -DHAVE_CONFIG_H -O2 -std=c++11)

Are all cmdline arguments replaceable by # lines? If not, what args are replaceable?

You mean replaceable by preprocessor directives. Read documentation of cpp

Actually, most compiler options are not replaceable by preprocessor directives; notably

  • -std=

  • -L and -l and any other options for the linker

  • -I and similar options for include directories

However, -O2 and some other optimization flags are settable by function attributes e.g. __attribute__((optimize("O2")) (see this) and by function specific option pragmas e.g.
#pragma GCC optimize "-O2". Notice that this is specific to GCC.

I recommend spending a few hours reading the documentation of GCC.

You might also perhaps change your spec file, but I don't recommend doing that.

Why would one ever want to compile with -O2 instead of -O3

Size. Of course if size does really matters (sometimes is does, like embedded), one would use -Os. But main difference at O3 is the (from you already mentioned) inlining. This can increase the generated code size (but it is faster). Maybe you want speed, but not at all (space) cost? Otherwise I would see no reason why not to use O3 (except you know of a gcc compiler bug that only occurs in your code at O3, but as long as you dont have an error, you cant reproduce at O2, I would not care).

Unable to resolve symbol

That _ZNSt8ios-base4InitD1Ev is not a C symbol but a C++ one.

$ echo _ZNSt8ios-base4InitD1Ev | c++filt

Gives no clue, but if you replace the - with a _ (a typo, maybe?):

$ echo _ZNSt8ios_base4InitD1Ev | c++filt
std::ios_base::Init::~Init()

So that is the destructor of an internal class of the C++ STD library. So you should check the libstdc++.so library instead libc.so.

My advice is to just compile your program using G++, so the C++ library is properly initialized. It is not intended to be loaded dynamically, and that's why the segmentation fault.

why use gcc and g++ compiler drivers for c and c++

The only differences between gcc and g++ are that:

  • when the driver is used to invoke the linker, g++ causes libstdc++ to be linked as part of "stdlibs", while gcc will link only libc.
  • g++ will compile .c, .h and .i files as C++ unless the -x option is specified.

Both drivers will compile C or C++ depending on either the filename extension, or command-line switches. If you invoke the compiler-driver for compilation only and invoke the linker (ld) directly, using gcc or g++ -x, it makes no difference which you use.

Equally, if you invoke the gcc driver for C++ code and explicitly link stdlibc++ it also makes no difference - so long as your crt0.o is not C-only - a C++ runtime start-up must invoke global static constructors before main()) - this is likely to already be the case.

The definitive word from the documentation:

3.3 Compiling C++ Programs

C++ source files conventionally use one of the suffixes ‘.C’, ‘.cc’, ‘.cpp’, ‘.CPP’, ‘.c++’, ‘.cp’, or ‘.cxx’;
C++ header files often use ‘.hh’, ‘.hpp’, ‘.H’, or (for shared
template code) ‘.tcc’; and preprocessed C++ files use the suffix
‘.ii’. GCC recognizes files with these names and compiles them as C++
programs even if you call the compiler the same way as for compiling C
programs (usually with the name gcc).

However, the use of gcc does not add the C++ library. g++ is a program
that calls GCC and automatically specifies linking against the C++
library. It treats ‘.c’, ‘.h’ and ‘.i’ files as C++ source files
instead of C source files unless -x is used. This program is also
useful when precompiling a C header file with a ‘.h’ extension for use
in C++ compilations. On many systems, g++ is also installed with the
name c++.

When you compile C++ programs, you may specify many of the same
command-line options that you use for compiling programs in any
language; or command-line options meaningful for C and related
languages; or options that are meaningful only for C++ programs. See
Options Controlling C Dialect, for explanations of options for
languages related to C. See Options Controlling C++ Dialect, for
explanations of options that are meaningful only for C++ programs.

If you want to use just one, I suggest you use gcc and separately invoke the linker or explicitly link -libstdc++. That way the compilation mode will be dependent on the filename extension. Using g++ -x to compile C code is just going to cause confusion.

ming32-make is using g++ instead of cc or gcc to compile a .c source file

mingw32-make (correctly IMO) treats the file system as case insensitive, so foo.c and FOO.C refer to the same file.

Your makefile lacks any explicit rule for your hello_world goal, so built-in implicit rules must be used; it seems that the COMPILE.C rule is being matched for hello_world.c, before the COMPILE.c rule; COMPILE.C is a default rule for compiling C++, so the appropriate compiler is used.

As you note, setting CXX = gcc is kludgy, and fundamentally wrong; it will break if your project expands to requiring mixed C and C++ components. A more appropriate solution is to provide your own rule ... either an explicit rule, or a pattern rule, to direct mingw32-make to use $(CC) for compiling *.c (and *.C) files, so that the built-in default rules will not apply. You can then keep CXX = g++ for compiling any *.cpp files, (recommended for compatibility with MSVC convention), which your project may include.

What is the difference between g++ and gcc?

gcc and g++ are compiler-drivers of the GNU Compiler Collection (which was once upon a time just the GNU C Compiler).

Even though they automatically determine which backends (cc1 cc1plus ...) to call depending on the file-type, unless overridden with -x language, they have some differences.

The probably most important difference in their defaults is which libraries they link against automatically.

According to GCC's online documentation link options and how g++ is invoked, g++ is equivalent to gcc -xc++ -lstdc++ -shared-libgcc (the 1st is a compiler option, the 2nd two are linker options). This can be checked by running both with the -v option (it displays the backend toolchain commands being run).

What is the main reason not to compile c code with g++?

To your generic question, there's no simple answer. C++ only supports a subset of C. If you want to write code that's valid and has the same sematics in both languages, you're very limited. Some examples of C code that's not valid C++ are:

  • Code that uses keywords of C++ that don't have a special meaning in C like class, this, new etc. To avoid confusion, you normally try to avoid these keywords in C, but it's of course not necessary.

  • C has designated struct and array initializers and they are often a good idea in a typical C project. You could write for example

    struct foo {int a; char b; short c; };
    struct foo x = { .b = 'x', .c = 42 };

    this isn't valid C++.

  • In C, you must write struct foo to refer to a structure with tag foo, while C++ allows to just write foo. This has a strange consequence when it comes to typedefs. In C, you could have

    struct foo;
    typedef struct bar foo;

    This is just an example, the code is confusing of course. But it's invalid code in C++, because it would be unclear what you refer to when just writing foo. Therefore, in C++, a typedef with the same name as a struct tag must refer to the exact same type.

  • C supports flexible array members as the last element of a struct like this:

    struct foo { int x; int a[]; }

    The size of a is determined when you allocate memory for that struct (adding n * sizeof(int)). This feature doesn't exist in C++

  • In C, pointer casts are almost always wrong, while they can be used in C++ for casting between a base class and a derived one. Therefore, C has the concept of a generic pointer void * that can be converted without a cast. In C++, converting to and from void * requires a cast like with any other pointer type.

These are just the examples that I could think of immediately, there are probably more. So yes, it's never a good idea to compile C code with a C++ compiler.


I used c in a project, and after some study, I found better method with some c++ libraries, but I really don't want to rewrite the code

For this problem, there's another simple solution. Divide your code into multiple translation units. There's no problem at all with a mixed C/C++ project, as long as the C and C++ source files are distinct.

So that means you factor out all the code using your C++ library in a C++ file and compile only that file with a C++ compiler. For the public interface of that C++ module, use extern "C" declarations and guard them with an #ifdef __cplusplus to hide them from the C compiler.

The structure could look like this (very simplified), if the part using C++ is in a translation unit called module here:

module.h:

#ifndef MODULE_H
#define MODULE_H

#ifdef __cplusplus
// the C++ compiler will see this causing all declarations in the block to have C linkage,
// the C compiler won't see it (skipped by the preprocessor)
extern "C" {
#endif

int module_foo(int arg);

#ifdef __cplusplus
}
#endif

#endif

module.cpp:

#include "module.h"
#include <mycpplib> // example

int module_foo(int arg)
{
// some C++ code using your C++ library
}

main.c:

#include "module.h"

int main(void)
{
int x = module_foo(42);
}

You could build a complete program like this:

gcc -c -omain.o main.c
g++ -c -omodule.o module.cpp

# link them together, using the C++ library libmycpplib:
g++ -oprogram main.o module.o -lmycpplib

Difference between CC, gcc and g++?

The answer to this is platform-specific; what happens on Linux is different from what happens on Solaris, for example.

The easy part (because it is not platform-specific) is the separation of 'gcc' and 'g++':

  • gcc is the GNU C Compiler from the GCC (GNU Compiler Collection).
  • g++ is the GNU C++ Compiler from the GCC.

The hard part, because it is platform-specific, is the meaning of 'CC' (and 'cc').

  • On Solaris, CC is normally the name of the Sun C++ compiler.
  • On Solaris, cc is normally the name of the Sun C compiler.
  • On Linux, if it exists, CC is probably a link to g++.
  • On Linux, cc is a link to gcc.

However, even on Solaris, it could be that cc is the old BSD-based C compiler from /usr/ucb. In practice, that usually isn't installed and there's just a stub that fails, wreaking havoc on those who try to compile and install self-configuring software.

On HP-UX, the default 'cc' is still a K&R-only C compiler installed to permit relinking of the kernel when necessary, and unusable for modern software work because it doesn't support standard C. You have to use alternative compiler names ('acc' IIRC). Similarly, on AIX, the system C compiler goes by names such as 'xlc' or 'xlc32'.

Classically, the default system compiler was called 'cc' and self-configuring software falls back on that name when it doesn't know what else to use.

POSIX attempted to legislate its way around this by requiring the programs c89 (originally) and later c99 to exist; these are the compilers compatible with the ISO/IEC 9899:1989 and 9899:1999 C standards. It is doubtful that POSIX succeeded.


The question asks about the differences in terms of features and libraries. As before, the answer is platform specific in part, and generic in part.

The big divide is between the C compilers and the C++ compilers. The C++ compilers will accept C++ programs and will not compile arbitrary C programs. (Although it is possible to write C in a subset that is also understood by C++, many C programs are not valid C++ programs). Similarly, the C compilers will accept C programs and will reject most C++ programs (because most C++ programs use constructs not available in C).

The set of libraries available for use depends on the language. C++ programs can usually use C libraries on a given platform; C programs cannot usually use C++ libraries. So, C++ has a larger set of libraries available.

Note that if you are on Solaris, the object code produced by CC is not compatible with the object code produced by g++ -- they are two separate compilers with separate conventions for things such as exception handling and name mangling (and the name mangling is deliberately different to ensure that incompatible object files are not linked together!). This means that if you want to use a library compiled with CC, you must compile your whole program with CC. It also means that if you want to use one library compiled with CC and another compiled with g++, you are out of luck. You have to recompile one of the libraries at least.

In terms of quality of assembler generated, the GCC (GNU Compiler Collection) does a very good job. But sometimes the native compilers work a bit better. The Intel compilers have more extensive optimizations that have not yet been replicated in GCC, I believe. But any such pontifications are hazardous while we do not know what platform you are concerned with.

In terms of language features, the compilers all generally hew fairly close to the current standards (C++98, C++2003, C99), but there are usually small differences between the standard language and the language supported by the compiler. The older C89 standard support is essentially the same (and complete) for all C compilers. There are differences in the darker corners of the language. You need to understand 'undefined behaviour', 'system defined behaviour' and 'unspecified behaviour'; if you invoke undefined behaviour, you will get different results at different times. There are also many options (especially with the GCC) to tweak the behaviour of the compiler. The GCC has a variety of extensions that make life simpler if you know you are only targetting that compiler family.

Compiling a .cpp file with c++ command instead of g++ (Linux)

Shouldn't it throw an error saying there is no c++ command available? and suggest us to use g++?

Weeelll, there are no regulations or standards that restrict or require c++ command to do anything, so there is no "should" or "shouldn't". However, it would be strongly expected that c++ is a working C++ compatible compiler, that supports similar or same flags as cc does.

does the terminal replace our c++ hello.cpp with g++ hello.cpp internally?

A terminal is the device that displays things. Terminal does not replace it, it has no effect on it.

Most probably your system designer, but maybe administrator or publisher or distributor or package designer (or anyone in the chain), configured your system to provide a command named c++. Usually, that command is a symbolic link to a working C++ compiler, usually g++ on Linux systems. On my system, /usr/bin/c++ program is just installed with package named gcc, but some systems allow it to be configurable.

It shouldn't do that right?

As stated above, terminal shouldn't replace commands, it has no effect on it.

This is expected since

It is expected since there is no command named c. There are endless other unknown commands.

cc is the good old name for a C compiler. c99 is the standardized name of C99 compatible compiler.

Why am not getting a similar error for the c++ hello.cpp?

Because a command named c++ exists on your system.



Related Topics



Leave a reply



Submit