I have the following code that throws a compile error when compiling x.cpp (conflicting declaration 'typedef struct THE_TYPE_STRUCT THE_TYPE', on last line in y.h, g++ 5.3.0):
// x.h file
struct THE_TYPE;
class C{
THE_TYPE * t;
};
// x.cpp file
#include "x.h"
extern "C"{
#include "y.h"
}
// y.h file
struct THE_TYPE_STRUCT {
int x;
};
typedef struct THE_TYPE_STRUCT THE_TYPE;
File y.h is a C header that can not be included at the beginning of the header x.h because of conflicting names with other header files, so I have to make a forward definition for THE_TYPE. Seems that it's not completely properly. How do I do it properly?
C is not the same as C++ and have different rules (for example, typedef struct THE_TYPE THE_TYPE; is useless -since implicit- in C++ but meaningful in C).
You should generate the preprocessed form (e.g. with g++ -C -E x.cpp > x.ii) then study it. A possible trick is to remove line information (starting with #) by running g++ -C -E x.cpp | grep -v '^#' > x.ii then recompile using g++ -Wall -c x.ii and look into the faulty locations in x.ii
Without knowing the actual files involved, we cannot help (e.g. perhaps some file has some #define THE_TYPE).
How do I do it properly?
In C++, you'll probably use namespace-s (notably in your own files) and avoid macros.
In C, you probably should edit your files, and I suggest to add a common prefix to every public name in your own code. You might take inspiration from GTK where every name is starting with Gtk or GTK or _GTK etc...
In general you need some consistent naming conventions and you probably need to edit all your files.
Change
struct THE_TYPE_STRUCT {
int x;
};
typedef struct THE_TYPE_STRUCT THE_TYPE;
to
typedef struct THE_TYPE_STRUCT {
int x;
}THE_TYPE;
I use the following scheme in my current project mixing a bit of c++11 code into a c11 codebase:
basedecl.h (included everywhere):
// [...]
#ifdef __cplusplus
# define pocaslibs___cdecl extern "C"
# define DECLDATA
# define C_CLASS_DECL(t) struct t
# define C_ENUM_DECL(t) enum t
#else
# define pocaslibs___cdecl
# define DECLDATA extern
# define C_CLASS_DECL(t) typedef struct t t
# define C_ENUM_DECL(t) typedef enum t t
#endif
// [...]
Forward-declaring struct types (also used for "private" types):
C_CLASS_DECL(PG_Menu);
C_CLASS_DECL(PG_Window);
Declaring "public" struct types:
C_CLASS_DECL(PG_Bounds);
struct PG_Bounds
{
unsigned int x;
unsigned int y;
unsigned int width;
unsigned int height;
};
Works quite nicely for both languages. The macro is named C_CLASS_DECL because in my codebase, this is really used for creating OO classes in c. If your usecase has nothing to do with OO, better think about a better name ;)
Related
I've stumbled across some code that looks like this:
typedef struct SomeStruct
{
int foo;
void * bar;
#if defined(__cplusplus)
SomeStruct();
#endif
} SomeStruct;
It's in a header file that will be included by both .c and .cpp files. That seems to be at least technically a violation of the One-Definition-Rule. The obvious impact I see is that if one of these is ever declared in .c file, the constructor won't run. And unfortunately, someone seems to have used this as a pattern for the correct way to declare structs, and has declared a couple dozen structs just like it.
I'm trying to figure out how serious a problem this is. Beyond the constructor possibly not running, is there any other likely impact? The constructor is implemented in a .cpp file. I see pointers to structs allocted in a .c file (with malloc) that are passed to functions in the .cpp files. They appear to work correctly (compiled with gcc/g++ 4.6.2 for Suse Linux, if that matters), as far as I can tell. Would something break if virtual member functions were also added? Right now, none of these classes have anything in their cplusplus section other than the default constructor, as shown above.
It's not exactly a violation of the ODR. Informally, the C compiler see a POD type and the C++ compiler see a class in the global namespace which will become an entity with a mangled name. More importantly, the structure is only declared differently for C and C++ compilers, but it is only defined once in a C++ source file. Most likely there's some allocation and free functions in a C++ source file which expose the constructor/destructor to a C API. For example,
Header file
$ cat some_struct.h
#ifndef SOME_STRUCT_H
#define SOME_STRUCT_H
typedef struct SomeStruct {
int foo;
void *var;
#if defined(__cplusplus)
SomeStruct();
#endif
} SomeStruct;
#if defined(__cplusplus)
extern "C" {
#endif
SomeStruct *some_struct_malloc();
void some_struct_free(SomeStruct **);
#if defined(__cplusplus)
} // extern "C"
#endif
#endif // SOME_STRUCT_H
C++ source file
$ cat some_struct.cpp
#include "some_struct.h"
#include <cstddef>
SomeStruct::SomeStruct()
{
foo = 10;
var = NULL;
}
SomeStruct *some_struct_malloc() { return new SomeStruct; }
void some_struct_free(SomeStruct **pp)
{
if (*pp)
delete *pp;
*pp = NULL;
}
C source file:
$ cat main.c
#include "some_struct.h"
#include <stdio.h>
int main()
{
SomeStruct *p = some_struct_malloc();
printf("%d\n", p->foo);
}
I would say it is a bad style. But it works as a convenient way to expose a C++ library to a C API
I am working on a huge project which has one file A.h whose code has a line
typedef unsigned __int16 Elf64_Half;
Also since I am building on Linux and using dlinfo function, I have to include link.h file in my project. And this is where it creates a conflict because I have two typedefs having the same name Elf64_Half. (Linux link.h includes elftypes.h and it too has: typedef unsigned short Elf64_Half;).
What do I do in such a case? Is the only option I have, to change my typedef in a.h? Remember it is not too easy because the project is huge and I will have to make a change in several places.
Is there a way to undef a typedef or something?
For clarification, Rahul Manne gave an easy solution. Do
#define Elf64_Half The_Elf64_Half_I_dont_care
#include<link.h>
#undef Elf64_Half
#include<A.h>
/*
* Code here and use Elf64_Half from A.h as you like.
* However, you can't use Elf64_Half from link.h here
* or you have to call it The_Elf64_Half_I_dont_care.
*
*/
This will substitute each Elf64_Half in link.h with The_Elf64_Half_I_dont_care and thus you get no conflicts with A.h. As long as you don't want to use Elf64_Half of link.h explicitly that will work with no problems. You just have to remember that Elf64_Half from link.h is now called The_Elf64_Half_I_dont_care in case you ever have to use it explicitly in this file.
What do I do in such a case?
A common remedy is to put the one which needs the least visibility behind a "compilation firewall". That is, to create your own abstraction/interface which provides the functionality you need, and then to limit the visibility of the included file to the *.cpp by including it in that *.cpp only. Of course, that *.cpp file would also not be permitted to include the header which has the other definition of the typedef.
Then the declarations won't cause conflict because they will never be visible to the same translation unit.
In your example, you'd likely create a wrapper over the dlinfo() functionalities you need. To illustrate:
DLInfo.hpp
namespace MON {
class DLInfo {
public:
/* ...declare the necessary public/client functionality here... */
int foo();
...
};
}
DLInfo.cpp
#include "DLInfo.hpp"
// include the headers for dlinfo() here.
// these includes should not be in your project's headers
#include <link.h>
#include <dlfcn.h>
// and define your MON::DLInfo implementation here, with full
// ability to use dlinfo():
int MON::DLInfo::foo() {
...
}
...
Here's a little work around I figured out: If you define it as something else first, then you can typedef it later. See here in the example (I'm on OS X using g++):
#import <iostream>
using namespace std;
typedef unsigned int uint32;
int main() {
cout << sizeof(uint32) << endl;
}
The output of this program is
4
Now consider this modified program:
#import <iostream>
using namespace std;
typedef unsigned int uint32;
#define uint32 blah
typedef unsigned long uint32;
int main() {
cout << sizeof(uint32) << endl;
}
The output of this program is
8
So to answer your question, you would add a line to your code:
#define Elf64_Half Elf64_Half_custom
For clarity, this works because you are basically renaming them all, but doing so with a single command instead of having to change all of your own names.
I have two .cpp files in one project, main.cpp and myfile.cpp
I have globaly defined struct mystruct in main.cpp, now I want to use this struct in myfile.cpp.
When I write mystruct in a header file and include in both cpp files I get an error, saying mystruct redefinition. How should I solve this problem.
If you are trying to share the definition of a struct among several compilation units (cpp files), the common way is this: Place the definition of your struct in a header file (mystruct.h). If the struct contains any methods (i.e. it is rather a class with all member public by default), you can implement them in mystruct.CPP file, or, if they're lightweight, directly within the struct (which makes them inline by default).
mystruct.h:
#ifndef MYSTRUCT_H
#define MYSTRUCT_H
struct MyStruct
{
int x;
void f1() { /* Implementation here. */ }
void f2(); /* Implemented in mystruct.cpp */
};
#endif
mystruct.cpp
#include "mystruct.h"
// Implementation of f2() goes here
void MyStruct::f2() { ... }
You can use your struct in as many cpp files as you like, simply #include mystruct.h:
main.cpp
#include "mystruct.h"
int main()
{
MyStruct myStruct;
myStruct.x = 1;
myStruct.f2();
// etc...
}
If, on the other hand, you are trying to share a global instance of the struct across several compilation units (it's not absolutely clear from your question), do as above but also add
extern MyStruct globalStruct;
to mystruct.h. This will announce that an instance is available with external linkage; in other words that a variable exists but is initialized elsewhere (in your case in mystruct.cpp). Add the initialization of the global instance to mystruct.cpp:
MyStruct globalStruct;
This is important. Without manually creating an instance of globalStruct, you'd get unresolved-external linker errors. Now you have access to globalStruct from each compilation unit that includes mystruct.h.
You should move the common struct to a header file and include that header in both files. Any other solution is a workaround.
The problem is that you basically have the same code twice as a result if you see an include as just a import of the code.
You can use #ifdef to fix it, see http://www.fredosaurus.com/notes-cpp/preprocessor/ifdef.html
Declaration and definitions are two different things. For your case, you are allocating space for your structure in main.cpp. In your header, you should use the extern modifier for your struct so that all files that include the header file will look in the global namespace for the structure. Hope it helps.
The standard C/C++ approach:
// source.h
Put all struct, class, typedef, macro definitions, extern variable declaraltions
// source.cpp
Implement the class, functions, define global/external variables
// main.cpp, and other parts of program
#include"source.h"
You should define structure in the header file only, you should remove definition from main.cpp
May be you can give more information about what is the layout of your project.
Going by the guess, probably your problem can be either of the two:
you want forward declaration of struct.
using include guards to prevent redefinition.
See the following link for how to handle both:
http://www.adp-gmbh.ch/cpp/forward_decl.html
The header files also use include guards, so you can figure out what exactly can solve your problem.
If you want to share any variable between multiple cpp files, you should declare it in header as extern. And without extern in one of that c++ files.
If you don't do it, it'll lack at linking, because multiple objects would have variable with same name. Instead when using extern one object would have this variable and other objects link it.
The header is where you declare what your struct will consist of (probably a common.h file included by main.cpp and myfile.cpp):
struct MyStruct {
int messageID;
int tempVariable;
};
In your main.cpp, this is where you actually use the struct:
void someFunction() {
struct MyStruct tempStruct;
// do something with it
tempStruct.messageID = 1;
}
Don't put the definition of your struct in both your main.h and main.cpp - or you will get a redefinition error!
Also, don't include the cpp file - include the header file (e.g. common.h). Without knowing more about the structure of your program, it is hard to provide better information.
When building my small C++ project, I get the following 2 errors, can't figure out the cause:
error: using typedef-name 'TTF_Font' after 'struct'.
Points to the following line of code: struct TTF_Font; in Foo.h.
error: 'TTF_Font' has a previous declaration here.
Points to the following line of code: typedef struct _TTF_Font TTF_Font; in SDL_ttf.h.
I've narrowed it down to the following files in a new test project:
Foo.h:
#ifndef FOO_H
#define FOO_H
struct TTF_Font;
class Foo
{
TTF_Font* font;
};
#endif // FOO_H
Foo.cpp:
#include "Foo.h"
#include "SDL/SDL_ttf.h"
// No implementation, just testing
Main.cpp:
#include "Foo.h"
int main(int argc, const char* argv[])
{
Foo a;
return 0;
}
Do you guys know what I'm doing wrong?
My goal is to forward declare TTF_Font, so I can use it in my header file without including the SDL_ttf header file. I read that including header files in other header files was kinda bad practice, so I switched to forward declarations. All my other forward declarations work fine except this single struct.
When I replace the forward declaration struct TTF_Font; with the header include #include "SDL/SDL.ttf.h", it compiles without errors. So I can use that, but I want to know WHY, dammit :-).
Extra info: I'm using the Code::Blocks IDE with mingw32 compiler. Project uses the SDL graphics library. Not much C++ experience yet, come from C# background.
You are trying to forward declare something as a different type to what it actually is.
You are declaring:
struct TTF_Font;
when the error message indicates that TTF_Font is actually a typedef, not a struct:
typedef struct _TTF_Font TTF_Font;
The stuct is actually called _TTF_Font.
You can declare the same typedef multiple times so you can just use the typedef declaration instead of the forward declaration to declare the struct and introduce the typedef although it does feel a bit like you are using implementation details of the header that you are trying to defer including.
The problem is that in this code snippet:
struct foo_t;
typedef struct foo { ... } foo_t;
The first line is a forward-declaration of a different struct, whose name clashes with the typedef. The forward declaration in this case needs to be struct foo;, because the name of the struct itself is foo.
I have the following chunk of a header file BKE_mesh.h:
/* Connectivity data */
typedef struct IndexNode {
struct IndexNode *next, *prev;
int index;
} IndexNode;
void create_vert_face_map(ListBase **map, IndexNode **mem, const struct MFace *mface,
const int totvert, const int totface);
void create_vert_edge_map(ListBase **map, IndexNode **mem, const struct MEdge *medge,
const int totvert, const int totedge);
Note that the header file was prepared for the possibility of being used in a C++ file, as it had:
#ifdef __cplusplus
extern "C" {
#endif
at the top of the file, and the needed finish at the bottom. But the class implementing it was written in C.
Next, whenever I try to #include the header file, I get an odd error. If the file has a .cpp extension, it compiles just fine, no complaints whatsoever. However, if I do:
#include "BKE_mesh.h"
inside of a file with a .c extension, I get the following errors:
expected ')' before '*' token
for the two last functions, in specific, the variable:
ListBase **map
in both classes. (Note that earlier in the header file, it declared, but not defined ListBase).
So, my question is: why is this valid C++ code, but not C code?
Thank you.
In C++ you can refer to struct names directly but in C you need to prepend the keyword struct.
void create_vert_face_map(struct ListBase **map, ... );
You could get around this by adding a typedef. Then you wouldn't have to modify the function declaration.
typedef struct ListBase ListBase;
Try running just the pre-processor for each case.
Comparing the result may show different header files.
If so, it may hint on the "C"-problem.