I have code written in C only. The main function is main.c, and it include other c files like #include "Flash.h".
I would like to keep the project working but to be able to add a cpp file .
I was told that I have to change the main to be
main.cpp
which will produce 250 errors on compilation- regarding the included c files
What's the proper way to turn the main file to cpp and still include C files ?
main.cpp :
#include "Flash.h"
int main(void)
{
....
}
I have read How to use C source files in a C++ project? which did not provide me a direct solution to the problem (my compiler will use c++ anyway).
EDIT:
Before someone will kill me for asking (don't know why you are so aggressive), I get only 3 kinds of errors 250 times :
'->' cannot appear in a constant-expression
'&' cannot appear in a constant-expression
a cast to a type other than an integral or enumeration type cannot appear in a constant-expression
EDIT 2 :
Here are some of the lines ( running using SDK for some RF chip ):
Most of the errors are from this section
typedef enum /*lint -save -e30 -esym(628,__INTADDR__) */
{
NRF_GPIOTE_TASKS_OUT_0 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[0]), /**< Out task 0.*/
NRF_GPIOTE_TASKS_OUT_1 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[1]), /**< Out task 1.*/
NRF_GPIOTE_TASKS_OUT_2 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[2]), /**< Out task 2.*/
NRF_GPIOTE_TASKS_OUT_3 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[3]), /**< Out task 3.*/
#if (GPIOTE_CH_NUM > 4) || defined(__SDK_DOXYGEN__)
NRF_GPIOTE_TASKS_OUT_4 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[4]), /**< Out task 4.*/
NRF_GPIOTE_TASKS_OUT_5 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[5]), /**< Out task 5.*/
NRF_GPIOTE_TASKS_OUT_6 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[6]), /**< Out task 6.*/
NRF_GPIOTE_TASKS_OUT_7 = offsetof(NRF_GPIOTE_Type, TASKS_OUT[7]), /**< Out task 7.*/
On these lines the same error repeat :
a cast to a type other than an integral or enumeration type cannot appear in a constant-expression
The #include directive in C++ is a literal inclusion of source code. Imagine your C source code in Flash.h included by main.c doing something incompatible with C++ like
typedef int class;
Now, in your main.cpp you have
#include "Flash.h"
It's exactly as if you had this code typedef int class; directly in your C++ source file - so it's an error.
If you have C source code with C headers, you don't need to use C++ at all!
If you want to write new C++ code and make it call old code (or vice-versa), just use the linker. Have C++ code include C++ headers, and separately, C code include C headers, and the linker will combine all your code into an executable.
To make your C and C++ parts work together, you need an additional header file. For example call it c-cpp-interface.h. Then include it in all your C and C++ source files:
#include "c-cpp-interface.h" // in C files
extern "C" {
#include "c-cpp-interface.h" // in C++ files
}
This file should be written in a common C/C++ subset language. That is, mostly, C language but with increased type safety (e.g. prototypes for all functions must be written fully, without the implied ... arguments).
Ideally, your existing C header file could be used as such. However, C header files often accumulate cruft, and it might be more practical to create a new file than clean the existing one(s).
Looking at the actual error messages you have (with offsetof), you should try to have as little code as possible in the C - C++ interface. Don't put implementation details (like values of various constants) there. Only have there the declarations/prototypes for functions that are called by the other language (C calling C++ or vice versa).
The question you post points out you need to wrap the inclues
extern "C" {
#include "cheader.h"
}
In your case,
extern "C" {
#include "Flash.h"
}
int main(void)
{
}
and in each cpp that wants to use C code, use extern "C" round the include.
Related
I need to have compile time constant in C code:
#define CLASSFROMCXX_SIZE /* compile time constant /*
In C++ code I could just write:
#define CLASSFROMCXX_SIZE sizeof(ClassFromCXX)
But I can't use ClassFromCXX in C code. I could write a function that returns sizeof(ClassFromCXX), but I need compile time constant, not some runtime value.
Is it possible to achieve without code generation? What existing code generation tools could I use to achieve this?
It is more a theoretical question, but as an example: I use some library written in C++ in C code, so I write wrapper in C. I have to store classes from C++ somehow. Related question is: How to call a c++ class and its method from a c file
But it uses heap allocation/stack allocation.
You can achieve the goal with Makefile or other compiling tools: compile a piece of C++ code to get the size of the class and assign the size to a macro. After that, you can pass the macro to compile your real code.
Take Makefile as an example:
CODE_TO_GET_SIZE := "\#include \"class_from_cxx.h\"\n\#include <iostream>\nint main() {std::cout << sizeof(ClassFromCXX);}"
CLASSFROMCXX_SIZE := $(shell printf $(CODE_TO_GET_SIZE) | g++ -x c++ - && ./a.out)
What you want is simply not possible. C does not understand C++ class definitions nor C++ object layout. Thus, there is no way a C compiler could compute the size of a C++ class…
I think your best bet here would be to turn the problem around. While C does not understand C++ classes, C++ does understand C structs (to some degree) and can link with C. Instead of a C++ class, define a C struct as well as functions that operate on objects of that type. These functions can be implemented and used across both, C and C++:
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
int a;
float p[3];
} SomeThing;
void SomeThing_construct(SomeThing* obj, int arg);
void SomeThing_destruct(SomeThing* obj);
void SomeThing_doYourThing(const SomeThing* obj, float x);
#ifdef __cplusplus
}
#endif
As pointed out by n314159, you could then add a wrapper class around this basic interface to use on the C++ side of things.
I would try to avoid going down the code generation path unless absolutely necessary. For code generation to compute the size of a C++ class means that it has to invoke a C++ compiler at some point. Preferably the exact compiler that will be used to compile the rest of the code with exactly the same flags that will be used to compile the rest of the code (C++ object layout does generally not just depend on the compiler but may even be affected by certain compiler flags). You will want to write a tool that generates a header file that contains the code you need. You will want to integrate the compilation and running of this tool into your buildsystem. Think of the generated header file as a dependency that is to be built like, e.g., a library would be. How you would go about doing this exactly depends on your build system. In a Makefile, you can just add a target to build the header file. If you use CMake to generate your buildsystem, you would add your tool using add_executable, then use add_custom_command() to define how the header file is to be built, and then add the generated header file to the sources of a target…
I'm trying to include mongoose web server, which is written in C, and write the rest of the code in C++.
When compiling I get the error: redeclaration of C++ built-in type 'bool' in the mongoose header file in Code Blocks
#include <iostream>
#include "mongoose.h"
using namespace std;
int main()
{
cout << "Hello world!" << endl;
return 0;
}
I enclosed the mongoose header in
#ifdef __cplusplus
extern "C"{
#endif
// header content
#ifdef __cplusplus
}
#endif
and I'm still getting the same error, at #include winsock2.h
C and C++ are different languages that share a common subset. You can compile most C declarations with a C++ compiler by putting them in a section specifying C linkage, as you show, but that follows from the sublanguage of C declarations being almost entirely within the shared subset of C and C++.
C++ has both more declarational features and more constraints than C does, however. In particular, the fact that it provides bool as a built-in type places a constraint that that identifier cannot be redeclared as a typedef name. C, on the other hand, has a standard header that defines exactly such a typedef, and it is not so uncommon for people to roll their own, too. Such typedefs will be rejected by a C++ compiler, C linkage notwithstanding.
If the C project is not already built with a mind toward providing for use by C++ programs, and simply wrapping the header inclusion in a C linkage block does not suffice, then you simply cannot use that library's header as-is. Your options are either to modify it or to provide an alternative. You might even need to provide a few wrapper functions, written in C, to serve as an interface with your C++ program. Details depend on the library you're trying to use.
If this is your only issue, then you could add #define bool C_INT_BOOL near your extern "C", then #undef bool near the }
In your cpp file I would write:
extern "C"{
#define bool C_INT_BOOL
#include "mongoose.h"
#undef bool
}
This allows the "C" interface to see the int parameter type, but shouldn't interfere with your c++ use of bool.
But I doubt this will be your only issue, in which case you will probaby quickly realise that adding an interface function layer is the safest way to go.
I am trying to use a supplier's library in combination with my C++ application. The library is largely based on C, which is normally not a problem with the extern "C" option, but I ran into an issue that the C++ compiler does not accept.
I simplified my code into the following example files. header.h represents a header from the suppier library, main.c/cpp are my own files. My real application is a C++ application, so I want to get it to work with main.cpp.
header.h (note the line u64 u64;):
#ifndef HEADER_H
#define HEADER_H
#include <stdint.h>
typedef uint64_t u64;
union teststruct {
u64 u64;
struct {
u64 x:32;
u64 y:32;
} s;
};
#endif
main.c:
#include <stdio.h>
#include "header.h"
int main() {
union teststruct a;
a.u64=5;
printf("%x\n", a.u64);
return 0;
}
main.cpp (same as main.c but with an extra extern "C" statement):
#include <stdio.h>
extern "C" {
#include "header.h"
}
int main() {
union teststruct a;
a.u64=5;
printf("%x\n", a.u64);
return 0;
}
Compiling main.c using the line
gcc -o test main.c
compiles without problems. However, compiling the C++ version using the g++ compiler with the command
g++ -o test main.cpp
gives the following compiler errors:
In file included from main.cpp:12:0:
header.h:11:9: error: ‘u64’ does not name a type
u64 x:32;
^
header.h:12:9: error: ‘u64’ does not name a type
u64 y:32;
^
The issue is that the supplier used the same name (u64) for both the type and the variable name, which seems like a bad idea to begin with, but gcc apparently accepts it. I do not want to change the library (i.e. header.h) as it is very large,this occurs a lot in the code, and I occasionally get updates for it. Is there a way to make g++ accept this combination, or a way to modify main.cpp to make it compile without changing header.h?
teststruct defines a scope in C++. You can form the qualified id teststruct::u64. So the language rules for name lookup account for that, allowing members of classes and unions to hide identifiers in outer scope. Once u64 u64; is introduced, the unqualified u64 cannot refer to the global ::u64, only the member. And the member is not a type.
In C union teststruct does not define a scope. The field can only be used in member access, so there can never arise a conflict. As such the field need not hide the file scope type identifier.
There is nothing, as far as I can tell, that you may do in order to easily work around it. This library (which is a perfectly valid C library), is not a valid C++ library. No different than if it used new or try as variable names. It needs to be adapted.
It seems that you have a header file that is illegal in C++, so you cannot #include it in code compiled as C++. If you cannot effect a change in the library header file (e.g. by complaining to your library supplier) then the most straightforward option is to write a thin C++-compatible wrapper around the library:
To isolate your C++ code against the C header, create a Wrapper.h and Wrapper.c, where the .h is valid for inclusion in C++, does not include header.h, and provides all types and functions that you need for library interaction. Then, in the .c, you can #include "header.h" and implement all the calls (and whatever you need to do to safely convert between the types). This would obviously have to be compiled as C, not C++.
If your mentioned incompatibility between C and C++ is the only one, you should be able to convert header.h to C++ compatible header file programmatically, name it something like header.hpp. And then you can convert newer versions the same way.
Compiler errors tell you everything about what and where should be changed:
header.h:11:9: error: ‘u64’ does not name a type
Open header.h;
Seek position 11:9;
Insert :: there;
Repeat for all does not name a type error.
Some string processing and it's done.
PS: C to C++ converters may able to do that too.
I have a C++ project that I have configured using Cmake to use Eclipse. My problem is that I have added a static C library (namely, svm-struct/svm-light) which doesn't seem to compile- and my guess is that it's compiling as C++ instead of C.
I added the library to my project as follows:
SET(SVM_LIGHT_SRC_DIR "../../Libraries/svm_rank")
INCLUDE_DIRECTORIES(${SVM_LIGHT_SRC_DIR})
ADD_LIBRARY(
svm_rank_lib STATIC
${SVM_LIGHT_SRC_DIR}/svm_light/svm_learn.c
${SVM_LIGHT_SRC_DIR}/svm_light/svm_common.c
${SVM_LIGHT_SRC_DIR}/svm_light/svm_hideo.c
${SVM_LIGHT_SRC_DIR}/svm_struct/svm_struct_learn.c
${SVM_LIGHT_SRC_DIR}/svm_struct/svm_struct_common.c
${SVM_LIGHT_SRC_DIR}/svm_struct/svm_struct_classify.c
${SVM_LIGHT_SRC_DIR}/svm_struct_api.c
${SVM_LIGHT_SRC_DIR}/svm_struct_learn_custom.c
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} svm_rank_lib)
Cmake configures fine it seems. Within the output of the configuration it specifies that it finds my C and C++ compilers and that they "work". I add the header to one of my project files using extern as follows:
#ifdef __cplusplus
extern "C" {
# include "svm_struct/svm_struct_common.h"
}
#endif
When I go to build my project the error is here:
../../Libraries/svm_rank/svm_struct/../svm_struct_api_types.h:75:11: error: expected member name or ';' after declaration specifiers
double *class; /* vector of scores that imply ranking */
~~~~~~ ^
1 error generated.
There is a variable within the library header called "class" where the error occurs, and my guess is that it's trying to compile this library header using C++ instead of C. First of all is this the reason for the error? If so, how should I go about fixing this?
As has already been pointed out, the source of the problem is that the C library header declares a variable named class, which is a keyword in C++.
This problem will hit you as soon as that header is pulled in by a C++ source file. Remember that headers are not compiled by themselves, but are merely copy-pasted by the preprocessor into the source file that #includes them. It is the type of the source file that determines whether the code in the header is interpreted as C or C++.
The fact that you wrapped the include in extern "C" does not change this. It simply switches off C++-style name mangling for the declarations in the header, but the code still has to compile as valid C++.
The cleanest solution to this problem is a technique known as insulation or compiler firewall.
You have to make sure that all parts that come into contact with the problematic library are C-source files themselves. The C++ part of your code only interacts with the library through the interface of that C part, but never with the library directly. In particular, you must never #include library headers from any of your header files.
For instance:
my_interface.c
#include "svm_struct/svm_struct_common.h" /* safe to include from a .c file */
struct opaque_ {
/* you can use types from svm_struct_common in here */
};
opaque* initialize()
{
/* you can create an opaque_ on the heap and
manipulate it here, as well as give a
pointer back to the C++ part */
}
void do_stuff(opaque*)
{
/* do whatever you like with the stuff in opaque */
}
my_interface.h
/* no #includes in the header! */
/* the opaque type is only forward declared!
C++ code can obtain a pointer to it,
but cannot look inside */
struct opaque_;
typedef struct opaque_ opaque;
opaque* initialize();
void do_stuff(opaque*);
my_application.cpp
// we only include our own header, which we made sure is valid C++
extern "C" {
#include <my_interface.h>
}
void do_stuff()
{
opaque* context = initialize();
do_stuff(context);
}
double *class; /* vector of scores that imply ranking */
class as highlighted in blue if it helps. Is a reserved word meaning you can't use it as a variable or macro name. Try changing it and it should remove the error.
Edit
I misunderstood you are compiling in C but it seems to compile in C++. But I still stand by my answer its best to change the variable class to keep the code compatible with C++ as class is a reserved word in C++.
According to my requirement.
Suppose I have below files
abc.h //used for C file
int new; // All C++ keywords, new use as a variable
char class; // All C++ keywords, class use as a variable
Actual_task();
abc.c //C file
main()
{
...//Body of file where they have used new and class variable
new++; //for an example
class = 'C';
actual_task();//One function is getting called here
}
I have a .cpp file which needs the file abc.h needs to be included to use actual_task():
CPPfile.cpp
extern "C"{
#include "abc.h"
}
Then it throws errors like class and new can not used just like a variable.
Then how to use the C header files in cpp files?
You can't use C header files that use C++ keywords for other purposes than what they are meant for in C++.
The proper solution is to change the header file so it does not use the C++ keywords any more.
If the C++ keywords are used for global variables (that are not used by the C++ code) or function parameter names, you might get away with a construct like this:
#define new new_
#define class class_
extern "C" {
#include "abc.h"
}
#undef class
#undef new
Change the headers so that the variables / functions don't have names which are reserved words in C++.
If anyone says you can't then tell them you're being ask to merge source code from two separate programming languages which are, in this sense, incompatible. It's a known issue with a known solution.