Splain like I'm 5 ....

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know that mixing C and C++ is like drinking warm Budweiser beer to many of you - I have done this thing.

 

Now I was getting all kinds of weird errors like thinking 'class' was a type etc. I looked for a good 60-90 minutes here for other people like me having these errors that are obvious to those more experienced or have done a better job of RTFM - likely both. Nonethelessy….

 

Why do all of my mix of files .C and .CPP all compile properly if I don't add them to the project as links? If I add them as links all of the weird compile errors start happening that weren't present before.

 

So looking around here someone suggested changing all the file name extensions to .cpp to help diagnose the problem. Well that sounds bloody easy- lets do that. It worked!

 

So my question to the gurus is please help me understand what misconception I'm having about translation units in Atmel Studio and the C and C++ compilers. 

 

I'm using as I always have when mixing C and C++ code

 

#ifdef __cplusplus

extern "C" {

#endif

 

in all of the C modules. 

 

Nonetheless it would seem the C compiler is translating files before the C++ compiler defined __cpluspus? Why does this behaviour only present itself when adding the files as links?

 

My simple workflow

 

New Project

inside Project Directory

   - Git init

   - Git submodule add NameofLibrary

 

Then inside the Atmel Studio IDE I simply add any files from NameofLibrary as links... 

 

It was supposed to be that simple... As the post asks if you have the time can you explain to me like I'm 5 what misconception I'm having here?

 

Thanks very much...

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you had written:

 

#ifdef __cplusplus

extern "C" {

#endif

My Excellent Code

...

...

 

#ifdef __cplusplus

}

#endif

 

in all of the C headers.

 

I would have been happier. Unless of course you are #including a C file within a c++ file then things get a bit tricky.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rediron wrote:

#ifdef __cplusplus

extern "C" {

#endif

 

I can only perhaps explain what the above is for, if you don't know.

 

In C, you can only have one function with a particular name.  With

C++, you can have many functions with the same name, as long as

each one has a unique combination of arguments allowing the

compiler to figure out which one you're using.

 

int foo (int x);
int foo (string s);  // OK, different argument type

 

The C++ compiler performs "name mangling" on the function names

to include the types of the function arguments so that they can be

distinguished:

 

foo_int_int
foo_int_string

(Actual name mangling is much worse than that!)  A C function should

just have the simple name foo without the encoded parameters, so

you have to tell the C++ compiler not to mangle the name using the

extern "C" directive.

 

This is why the .c or .cpp file suffix is important.  If it's .c then functions

are compiled using C rules and do not have their function names mangled.

 

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avr-mike wrote:
(Actual name mangling is much worse than that!) 
An example:

int foo (int x) {}
int foo (float f) {}

int main(void) {
	while(1) {
	}
}

leads to:

 .text._Z3fooi  0x0000006c        0x2 main.o
                0x0000006c                _Z3fooi
 .text._Z3foof  0x0000006e        0x2 main.o
                0x0000006e                _Z3foof
 .text.main     0x00000070        0x2 main.o
                0x00000070                main

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

 .text._Z3fooi  0x0000006c        0x2 main.o
                0x0000006c                _Z3fooi
 .text._Z3foof  0x0000006e        0x2 main.o
                0x0000006e                _Z3foof
 .text.main     0x00000070        0x2 main.o
                0x00000070                main

Now try:

namespace blah {

class bar
{
    int foo (int x);
};

}

 

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah yes, that leads to utter madness:

#include <avr/io.h>

namespace blah {

	class bar
	{
		public:
		__attribute__((noinline)) int foo (int x) { PORTB = 0x55; }
		__attribute__((noinline)) int foo (float f) { PORTB = 0xAA; }
	};
}

blah::bar boom;

int main(void) {
	boom.foo(123);
	boom.foo(3.14f);
	while(1) {
	}
}

yields:

0000007c <_ZN4blah3bar3fooEi>:
namespace blah {

	class bar
	{
		public:
		__attribute__((noinline)) int foo (int x) { PORTB = 0x55; }
  7c:	85 e5       	ldi	r24, 0x55	; 85
  7e:	88 bb       	out	0x18, r24	; 24
  80:	08 95       	ret

00000082 <_ZN4blah3bar3fooEf>:
		__attribute__((noinline)) int foo (float f) { PORTB = 0xAA; }
  82:	8a ea       	ldi	r24, 0xAA	; 170
  84:	88 bb       	out	0x18, r24	; 24
  86:	08 95       	ret

surprise

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why mix C and C++ in the first place?

Why not simply compile all of your C and C++ code with the C++ compiler.

Then it can mangle all the names as much as it wants and us, mere mortals, won't even notice.

 

I'm no expert with C++, but from what I understand the " extern "C" " is only mandatory if for example you have pre compiled libaries which were compiled with a C compiler, and want to call functions from those libraries with your C++ compiler.

A C++ compiler is perfectly capable of compiling C code.

 

There are also multiple ways in which GCC can be told how to compile your code. (It is actually hundreds of different options). The default is to compile .c files with a C compiler and .cpp files with a C++ compiler. 

 

I say here "a" C compiler and not "the" C compiler because GCC acutally is a collection of compilers. If you want GCC to compile according to iso9899:1990 then use -std=c90

If you want GCC to compile to a more recent C++ standard you can for example use =std=c++14. A quick count of "man gcc" gives 26 different versions of C and C++ that GCC can conform to.

Do not ignore those. There have been some nice additions to C++ in the later years and if you are into C++ you should read up on them.

https://isocpp.org/

 

You also mention that things only go wrong if you use symbolic links as file names. If you're still having troubles, then tell us more about that. Then also post (at least some) of the error messages you are getting. Just copy and paste the actual text. This is often much more usefull than your interpretation of what that text means.

 

On my linux box I had some troubles with symbolic links in combination with Code::Blocks. I forgot the details, but the problems were severe enough to abandon Code::Blocks and get another IDE. The problems with links in Code::Blocks have apparently been fixed some years ago, but I'm quite happy with the IDE I have now and have no reason to invest time in Code::Blocks.

It's the good side of makefiles. Once they work, the IDE you use is pretty much interchangable, but is is nice if you can configure it to save all your files and spit out a "make all" or "make program" with a single button press. I usually try to configure some of the function keys to do this. I hate (strongly dislike?) programmer interfaces with a GUI.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paulvdh wrote:

Why mix C and C++ in the first place?

 

Side-effect of drinking warm Budweiser??

--Mike

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why mix C and C++ in the first place?

Isn't there an issue with C++ not knowing about the 'flash' data attribute? The C compiler does know about it, but the C++ complier doesn't? That's why I sometimes write plain C files for Arduino (trying to avoid the PROG_MEM stuff). Maybe I'm all wrong about that...

Mike

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mha11 wrote:
Maybe I'm all wrong about that...
No as the Embedded C standard has address spaces that are partially implemented in AVR GCC.

TR 18037: Embedded C (open N1169, page 45)

 

"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mha11 wrote:
Maybe I'm all wrong about that...
Nope, it's a very valid reason to have some .c alongside the .cpp's

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Ah yes, that leads to utter madness:

Sisboombah?

https://www.youtube.com/watch?v=...

"Describe the sound made when a sheep explodes."

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.