Wire.h mingles C++ and C

Hi
I was trying to create a sketch in my eclipse environment in Arduino 1.0 using the wire library.
The compilation failed. Investigation pointed out that my eclipse plugin compiles all files as C++ files where the Arduino IDE has the compiler select the C or C++mode.
As a consequence of this twi.c is compiled as C code and wire.cpp is compiled as C++ code in the Arduino IDE. In my plugin they are both compiled as C++.
wire.cpp includes twi.h as follows:

extern "C" {
  #include <stdlib.h>
  #include <string.h>
  #include <inttypes.h>
  #include "twi.h"
}

where twi.c includes twi.h as follows:

#include "twi.h"

As a consequence twi.h is always compiled as C in the arduino IDE. However in the eclipse plugin it is compiled as C in wire.cpp an as C++ in twi.c.
I accept this can not be called a bug but I feel it would be nicer to change twi.h so that there is encapsulation of twi.h. (no need for extern "C" in wire.cpp). twi.h would look as follows:

/*
  twi.h - TWI/I2C library for Wiring & Arduino
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#ifndef twi_h
#define twi_h

  #include <inttypes.h>

  //#define ATMEGA8

  #ifndef TWI_FREQ
  #define TWI_FREQ 100000L
  #endif

  #ifndef TWI_BUFFER_LENGTH
  #define TWI_BUFFER_LENGTH 32
  #endif

  #define TWI_READY 0
  #define TWI_MRX   1
  #define TWI_MTX   2
  #define TWI_SRX   3
  #define TWI_STX   4
#ifdef __cplusplus
extern "C" {
#endif
  void twi_init(void);
  void twi_setAddress(uint8_t);
  uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t);
  uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t);
  uint8_t twi_transmit(const uint8_t*, uint8_t);
  void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
  void twi_attachSlaveTxEvent( void (*)(void) );
  void twi_reply(uint8_t);
  void twi_stop(void);
  void twi_releaseBus(void);
#ifdef __cplusplus
 }
#endif

#endif

Could this be changed?
Best regards
Jantje

As a consequence twi.h is always compiled as C in the arduino IDE. However in the eclipse plugin it is compiled as C in wire.cpp an as C++ in twi.c.

No. Header files are included in source files that are compiled. Header files by themselves are not compiled.

PaulS:

As a consequence twi.h is always compiled as C in the arduino IDE. However in the eclipse plugin it is compiled as C in wire.cpp an as C++ in twi.c.

No. Header files are included in source files that are compiled. Header files by themselves are not compiled.

However, ignoring terminology, the thrust of his argument, and the file changes he has proposed are correct.

extern "C" should only be used when the header is being included in a C++ source file.

Iain

Paul
If it is not called "compiling" what the compiler does with the header file included in a *.c or *.cpp file during compilation; how is it called?

Who can answer the question "Could this be changed?"

Jantje

header file inclusion happens before compilation. It happens while/before the .cpp/.c is passed to the tokenizer

Open an issue on the Arduino google code page. Include a patch.

Doesn't make a lot of sense to change. Arduino is geared toward the IDE not Eclipse, anyway. You can always make the change locally and you're good.

As a consequence of this twi.c is compiled as C code and wire.cpp is compiled as C++ code in the Arduino IDE. In my plugin they are both compiled as C++.

I think that makes your plugin broken. Probably in easily fixable ways. I don't think there's a reason to change .c files in the arduino distribution so that they compile even when treated as c++, even if that's possible.

Maniacbug
Thanks for the link to the "open issue". I created one for this.
I agree it doesn't make much sense from an Arduino IDE point of view.
It is however hardly any work (I included the better twi.h) and results in better code quality.

best regards
Jantje

PS I've found a way around it.

What consequences does this issue have, does it cause problems at run time communicating with I2C devices?

Can you add a link to the issue you created for this, I cannot seem to find it.

thanks,
Chris

Chris
The consequences are only visible for people writing their own tools on top of the Arduino library.
Basically you can not compile twi.c with the C++ compiler.
Further on I think it is a matter of taste on whether you prefer self containment and robustness or strict language layering (C code should not know about C++). Probably other arguments exist as well for both options.
Technically it is about the fact that C++ does name mangling and C does not. See Name mangling - Wikipedia for more info on name mangling.

You can easily find the ticked by following the create ticked link and searching for Wire.h

Best regards
Jantje

I downloaded your plugin (1.2.5.5) and changed my default "twi.h" for you listed code. Unfortunately, I am still not able to compile my project since I receive this error messages:

**** Build of configuration Release for project WB_MCU1 ****

make all
Building file: /Applications/Arduino1.app/Contents/Resources/Java/libraries/Wire/utility/twi.c
Invoking: AVR Compiler
avr-gcc -I"/Applications/Arduino1.app/Contents/Resources/Java/hardware/arduino/cores/arduino" -I"/Applications/Arduino1.app/Contents/Resources/Java/hardware/arduino/variants/mega" -I"/Users/arduino/Documents/workspace/WB_MCU1" -I"/Users/arduino/Documents/Arduino1/libraries/RTClib" -I"/Applications/Arduino1.app/Contents/Resources/Java/libraries/Wire" -D__IN_ECLIPSE__=1 -DARDUINO=101 -DUSB_PID= -DUSB_VID= -Wall -Os -g -mmcu=atmega2560 -DF_CPU=16000000UL -MMD -MP -MF"Wire/utility/twi.d" -MT"Wire/utility/twi.d" -c -o "Wire/utility/twi.o" "/Applications/Arduino1.app/Contents/Resources/Java/libraries/Wire/utility/twi.c"
/Applications/Arduino1.app/Contents/Resources/Java/libraries/Wire/utility/twi.c:115: error: conflicting types for 'twi_readFrom'
/Applications/Arduino1.app/Contents/Resources/Java/libraries/Wire/utility/twi.h:45: error: previous declaration of 'twi_readFrom' was here
/Applications/Arduino1.app/Contents/Resources/Java/libraries/Wire/utility/twi.c:192: error: conflicting types for 'twi_writeTo'
/Applications/Arduino1.app/Contents/Resources/Java/libraries/Wire/utility/twi.h:46: error: previous declaration of 'twi_writeTo' was here
make: *** [Wire/utility/twi.o] Error 1

**** Build Finished ****

My Wire.cpp tab has these lines with a bug sign:

uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);

int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);

Am I missing a step?

Thank you.

Globe,

I have the same probleme. I have also changed twi.h according to the sugestion from Jantje.

Did you solve the problem?

Best regards

Georg