1

I was looking at Glew's header and I ran across something that raised a question for me:

// C
typedef struct __GLsync *GLsync;

I understand that Glew is a C library, therefore different from C++ and I know that this is a valid code in C++:

// C++
struct S { ... }; // S defined in the class name space
void f( S a ); // struct is optional

My question is, is it safe to remove the struct keyword from the typedef in C++ and include the header in a C++ only project?

typedef /*struct*/ __GLsync *GLsync;

If not, what would be the difference when I do a typedef with struct keyword and without it?

Sepehr
  • 1,897
  • 17
  • 28
  • Why do you want to remove it? – user93353 Sep 16 '14 at 16:28
  • 1
    The correct way to mix C and C++ code is with "extern". – BadZen Sep 16 '14 at 16:29
  • To address your question more directly, though - in C++ 'struct' is very, very similar to 'class'. But there are some differences. If you want a plain old C struct, "extern". – BadZen Sep 16 '14 at 16:30
  • @user93353 I do not want to remove it, I am just wondering because it looks cleaner without the `struct` keyword to me. – Sepehr Sep 16 '14 at 16:30
  • 2
    The former (with `struct`) will compile regardless of whether `__GLsync` is previously declared or not in the same translation unit, declaring a typedef of a pointer to some structure type (which may not be known at that point) called `_GLsync`. The latter (without `struct`) requires prior definition of the actual structure, or you will have an unknown type error. – WhozCraig Sep 16 '14 at 16:30
  • @WhozCraig So with `struct` keyword, it also forward declares the structure as well? – Sepehr Sep 16 '14 at 16:34
  • @BadZen: You mean `extern "C"`, not just `extern` – Keith Thompson Sep 16 '14 at 16:34
  • I meant "using the keyword 'extern'", but yeah, that's how you use it. (You forgot the {}! :) ) – BadZen Sep 16 '14 at 16:36
  • 1
    @3p3r yes, something like that. You can `typedef struct Something *SomeThingPtr;` without prior encounter of `Something` in the translation unit. The compiler will see it, and simply deduce "I don't know what this is, but I don't really need to know to declare a pointer alias to one." That is markedly different than `typedef Something *SomethingPtr;` which must have prior knowledge of what `Something` is. Of course by the time any code actually attempts to *dereference* a `SomethingPtr` the definition of `Something` has to have made its way into the translation unit. This is common in pimpls. – WhozCraig Sep 16 '14 at 16:39
  • @WhozCraig Could you please make it an answer? that's what I was looking for. Thanks! – Sepehr Sep 16 '14 at 16:43
  • @BadZen: What does `extern` have to do with it? The question is about `struct` type. It has absolutely nothing to do with linkage specifications. – AnT Sep 16 '14 at 16:58

3 Answers3

3

A typedef of the following form:

typedef struct S *SPtr;

does not need prior knowledge of what S is in the same translation unit. It assumes a forward declaration of some structure S and aliases SPtr as a pointer type to said-same. However, this:

typedef S *SPtr; // error unless S is declared earlier 

requires the declaration of the type S (which may be a structure) is already known prior to the declaration of the pointer alias type.

While this may seem trivial, it is a cornerstone of common implementations of the pimpl idiom. Note the typedef isn't really involved here, the announcement of struct MyClassImpl* as a pointer type to an unknown "thing" to-be-determined later (but prior to actual dereference) is what is important:

MyClass.h

#ifndef MY_CLASS
#define MY_CLASS

class MyClass
{
   ... members ...

private:
    struct MyClassImpl * m_pimpl; // note no MyClassImpl yet known
};

#endif

MyClass.cpp

#include "MyClass.h"  

// implementation formal declaration and implementation.
struct MyClassImpl
{
    ... members...
};

// MyClass implementation using the now-known MyClassImpl

Had that pointer been declared as:

MyClassImpl * m_pimpl;

the type MyClassImpl would require prior declaration or a compile-time error would ensue.

I hope that helps identify a key difference between the two methods of declaration. (and yes, I know, I should have used a smart pointer =P)

Best of luck.

Community
  • 1
  • 1
WhozCraig
  • 59,130
  • 9
  • 69
  • 128
1

The real answer here is maybe. It depends on what other code is found before it.

That being said, you can absolutely change this:

typedef struct __GLsync *GLsync;

To this:

struct __GLsync;
typedef __GLsync *GLsync;
Bill Lynch
  • 72,481
  • 14
  • 116
  • 162
  • Well this just looks cleaner to me. It clearly shows that something is being forward declared and then being used in a `typedef` and I actually ended up doing this in my code. Thanks! – Sepehr Sep 16 '14 at 16:59
0

If you want to remove struct keyword from typedef then you have to do things like this:

typedef struct S { ... }__GLsync; // S defined in the class name space

then you can use:

typedef  __GLsync  *GLsync;

Appended Question:

If struct is already definded by already some else then how to do work around then

 typedef struct __GLsync  *abc;
 typdef  *abc       GLsync

You can do things like this

Vineet1982
  • 7,211
  • 4
  • 28
  • 62
  • Thanks for the answer! but this involves defining the `struct` myself, which sometimes is impossible since the `struct` is defined somewhere else and all I want to do is a simple `typedef` – Sepehr Sep 16 '14 at 16:44