I'm trying to use Enums within a struct, this compiles and works fine with gcc.
But the same code when compiled with g++ throws an error.
#include<stdio.h>
#include<stdlib.h>
struct foo
{
enum {MODE1, MODE2, MODE3} mode;
enum {TYPE1, TYPE2} type;
};
void bar(struct foo* bar)
{
bar->mode = MODE1;
}
int main()
{
struct foo* foo = (struct foo*) malloc(sizeof(struct foo));
bar(foo);
printf("mode=%d\n",foo->mode);
}
Output obtained with gcc:
$ gcc foo.c
$ ./a.out
mode=0
Output obtained with g++:
$ g++ foo.c
foo.c: In function ‘void bar(foo*)’:
foo.c:11: error: ‘MODE1’ was not declared in this scope
MODE1 is in the scope of foo, so you need
bar->mode = foo::MODE1;
Note that if you want to access the enum types without a scope, you would need to declare them so. For example:
typedef enum {MODE1, MODE2, MODE3} MODE;
typedef enum {TYPE1, TYPE2} TYPE;
struct foo
{
MODE mode;
TYPE type;
};
Related
I have C/C++ mix code and want to pass around a struct that contains a reference to a class. Because of this, I can't declare this struct in the header file of the C++ component (because class is defined in source file of C++ component) but only in the source file. The main script in C however has to reference that struct somehow, so I typedef it to void*. However because of that, I can't dereference the handle type back to a struct. Redefining the handle pointer in the source file is not possible. How can I work around this?
header_with_obj.hpp
class A {
int a;
};
header.hpp
typedef void* config_handle_t;
source.cpp
#include "header.hpp"
#include "header_with_obj.hpp"
typedef struct {
A* ptr;
int some_other;
} config_t;
// typedef config_t* config_handle_t <-- error: conflicting declaration 'typedef struct config_t* config_handle_t '
int foo(void* arg)
{
config_handle_t handle = (config_handle_t) arg;
handle->A.a = 4; // <-- error: 'config_handle_t' {aka 'void*'} is not a pointer-to-object type
}
main.c
#include "header.hpp"
int main()
{
// we get that void* from somewhere and pass it in
foo(arg);
}
The usual way to do this is to use an undefined struct. In its most basic form:
void foo(struct the_config_struct *arg);
// OK even though 'struct the_config_struct' wasn't defined!
// surprisingly this is also allowed in C++
You can also make a typedef:
typedef struct the_config_struct *config_handle_t;
void foo(config_handle_t arg);
and if you want, you can even call the typedef the same thing as the struct. Just to avoid confusing people, I wouldn't do this unless it's a typedef for the struct (not a pointer).
typedef struct the_config_struct the_config_struct;
void foo(the_config_struct *arg);
You don't to actually have defined the struct until you want to access its members:
// if we uncomment this definition then it's OK
// struct my_struct {
// char *message;
// };
void foo(struct my_struct *arg) {
puts(arg->message); // error: struct my_struct is undefined
}
Finally (since this confused you before) you should know that typedef names and struct names are completely separate in C.
struct foo {}; // defines "struct foo" but "foo" is completely unrelated
typedef int bar; // defines "bar" but "struct bar" is completely unrelated
foo *get_foo(); // error: "foo" is unknown
struct foo *get_foo(); // OK
typedef struct bar foo;
foo *get_bar(); // OK: returns pointer to struct bar (not struct foo!)
struct foo *get_foo(); // this one returns pointer to struct foo
struct baz {};
typedef struct baz baz;
// now "baz" is an alternative name for "struct baz" - they are interchangeable
typedef struct baz {} baz; // short version
and structs don't have to have names:
// foo is a variable, and it's a struct variable, but the struct has no name.
// so we have no way to use the struct for anything else.
struct {
int i;
} foo;
// The struct is still there even though it doesn't have a name!
// In C++ you can write decltype(bar) to say "the same type as variable bar".
// Even though we don't know the person's name we can still yell out "Hey you in the red shirt!"
decltype(foo) foo2; // a variable foo2. The type is decltype(foo) i.e. the struct from before
// GCC lets you do it in C using "typeof".
// This is not standard. It's a special feature in GCC.
typeof(foo) foo2;
// This struct also has no name either. But the typedef means we have
// an "unofficial" way to name it, just like decltype(foo) before.
// This is valid in C as well as C++.
typedef struct {
char message[50];
} bar;
I am trying to execute following code using g++ and getting incomplete type error
#include <stdio.h>
struct try_main{
union{
struct try_inner_one{
int fl;
float g;
}one;
struct try_inner_two{
char a;
}two;
}un;
int chk;
};
void func(struct try_inner_one o){
printf("%d\n",o.fl);
}
int main(){
struct try_main z = {{1,2},3};
func(z.un.one);
return 0;
}
Error:
union.c: In function ‘void func(try_inner_one)’:
union.c:15:6: error: ‘o’ has incomplete type
void func(struct try_inner_one o){
^
union.c:15:18: error: forward declaration of ‘struct try_inner_one’
void func(struct try_inner_one o){
^
union.c: In function ‘int main()’:
union.c:20:16: error: parameter 1 of ‘void func(try_inner_one)’ has incomplete type ‘try_inner_one’
func(z.un.one);
Above code is successfully getting compiled with gcc
What is the reason for this error and how to fix this
Thanks
C and C++ have different scoping rules. The full name of the type in C++ isn’t struct try_inner_one, since the type definition is nested inside the unnamed union inside try_main.1
If you want to write code that works equally in both C and C++, pull the type definition to the top level:
struct try_inner_one {
int fl;
float g;
};
struct try_inner_two {
char a;
};
struct try_main {
union {
struct try_inner_one one;
struct try_inner_two two;
} un;
int chk;
};
1 The fully qualified name of this type can’t be spelled in C++ since the type it’s nested inside is unnamed. You could give a name to the union type, that would allow you to spell the fully qualified name of try_inner_one in C++. However, that name wouldn’t be legal C code, since C doesn’t have a scope resolution operator.
If you want to keep the nested type definition you could give the union a name (in the following, union_name) and do the following to keep the code compiling for both C and C++:
// (Type definition omitted.)
#ifdef __cplusplus
using try_inner_one = try_main::union_name::try_inner_one;
#else
typedef struct try_inner_one try_inner_one;
#endif
void func(try_inner_one o){
printf("%d\n", o.fl);
}
What is the reason for this error
The reason is that try_inner_one nested within the union nested within try_main cannot be found by unqualified name lookup in the context outside of that union in C++ (unlike in C).
how to fix this
You can use a qualified name in C++:
void func(decltype(try_main::un)::try_inner_one o){
You can simplify if you give a name for the union:
union u { // note the name
struct try_inner_one{
void func(try_main::u::try_inner_one o){
A cross-language compatible solution is to define the struct outside of each other as described in Kondrad Rudolph's answer.
A word of warning: C++ is more restrictive than C on how inactive members of union can be accessed.
It seems you are compiling your program as a C++ program. In this case each declaration within the structure try_main has the scope of this structure.
So you need to declare the function like
void func( decltype( try_main::un )::try_inner_one o );
or
void func( const decltype( try_main::un )::try_inner_one &o );
I'm trying to understand function declaration using typedefs.
What does this code do in C++?
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
fcn_t *pf;
ptr_t pf2;
In my understanding:
fcn_t is the type of a function, and so the line with f is a function declaration (not a definition), and I could later define it like void f(void) { blabla(); bleble(); } just as if I had declared void f(void); instead of fcn_t f;;
fcn_t * is the type of a function pointer, and the line with pf is a pointer variable definition, and pf is default-initialized (assuming the code excerpt is from the global scope);
There is no difference between fcn_t* and ptr_t, thus everything I said about pf applies to pf2.
Did I get it right? Would any of the three declarations have its meaning changed if I marked them extern? What would change if the code was compiled as C instead of as C++?
Yes you are right on all three counts. The only thing that would change if you marked them extern are the function pointers. Function declarations are by default extern in C++.
Try and compile the following program
template <typename...>
struct WhichType;
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
// constexpr auto one = WhichType<fcn_t>{};
// constexpr auto two = WhichType<fcn_t*>{};
// constexpr auto three = WhichType<ptr_t>{};
fcn_t f;
void f() {}
int main() {
f();
}
Uncommenting the commented lines will likely give you a compiler error that tells you what types the WhichType instance is being instantiated with, and as a result it should show you the exact types of all three things you asked about. It's a trick I picked up from Scott Meyers' book "Effective Modern C++".
To test whether the declarations are extern or not, write two simple implementation files, with one containing the definition of the variable
main.cpp
template <typename...>
struct WhichType;
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
int main() {
f();
}
definition.cpp
void f() {}
and then compile, link and run definition.cpp and main.cpp (via g++ -std=c++14 definition.cpp main.cpp and then ./a.out). If the declaration was not extern then the compile would fail with an undefined symbol error.
Here is a simple illustration of these typedef
#include <stdio.h>
typedef void fcn_t(void);
typedef void (*ptr_t)(void);
fcn_t f;
fcn_t *pf;
ptr_t pf2;
void
f(void)
{
printf("I am void\n");
}
void
vSayHi(void)
{
printf( "Hi\n" );
}
int
main(void)
{
pf2 = vSayHi;
pf2();
pf = vSayHi;
pf();
f();
return 0;
}
OUTPUT:
Hi
Hi
I am void
namespace MyNS {
template <>
class Test<Test1> {
public:
constexpr static char const *description[] = { "X`", "Y1"};
/*
...
...
*/
}
constexpr char const * Test<Test1>::description[];
/* Above definition is required when compiling with GCC but MSVC compiler gives error saying 'description' is redeclared. */
/* **Omitting definition of 'description', which is written outside class in namespace, causes successful compilation by MSVC but failure in GCC** */
}
Is there a common way to define, declare and initialize above constexpr such that code compiles successfully by both MSVC and GCC?
This code:
#include <iostream>
namespace MyNS {
template<class T> struct Test;
template <>
struct Test<int> {
constexpr static char const * description[] = { "X1", "Y1"};
};
}
int main() {
std::cout << MyNS::Test<int>::description[0];
return 0;
}
Compiles -as far as I can tell- using
g++-4.8+ -std=c++11
g++-4.8+ -std=c++1y
g++-4.9+ -std=c++14
g++-6.1+
g++-6.1+ -std=c++11
g++-6.1+ -std=c++14
without and further definition (where 4.8+ means starting from g++ version 4.8 and onwards).
Using the following code:
#include <stdio.h>
struct my_struct {
int a;
int b;
my_struct();
};
my_struct::my_struct(void)
{
printf("constructor\n");
}
void my_struct(void)
{
printf("standard function\n");
}
int main (int argc, char *argv[])
{
struct my_struct s;
s.a = 1;
s.b = 2;
printf("%d-%d\n", s.a, s.b);
return 0;
}
I get a warning compiling with g++ -Wshadow main.cpp:
main.cpp:15:20: warning: ‘void my_struct()’ hides constructor for ‘struct my_struct’
I would be ok with that warning if the void my_struct function actually replaced the my_struct::my_struct one. But it does not appears to be the case. If I run the program, I get:
constructor
1-2
Any idea what this warning mean ? It is quite annoying especially when I include C headers into C++ code
The warning points out that the my_struct() function has the same name as the my_struct structure. It means you will be unable to write:
my_struct s; // Error.
Because the compiler will think that you're using a function as a type. However, as you probably realized, you can still instantiate your structure with the struct keyword:
struct my_struct s; // Valid.
void my_struct(void) has the same name of your class/struct and since it is in the global namespace it is conflicting with your class/struct's constructor.
You could try something like:
#include <cstdio>
struct my_struct {
int a;
int b;
my_struct();
};
my_struct::my_struct(void)
{
printf("constructor\n");
}
namespace mbonnin
{
void my_struct(void);
}
void mbonnin::my_struct(void)
{
printf("standard function\n");
}
int main (int argc, char *argv[])
{
my_struct s;
s.a = 1;
s.b = 2;
printf("%d-%d\n", s.a, s.b);
mbonnin::my_struct();
return 0;
}
And by the way the struct in struct my_struct s; is redundant in C++.
warning: ‘void my_struct()’ hides constructor for ‘struct my_struct’
Any idea what this warning mean ?
It means that sometimes the warnings issued by the GNU compiler suite are a bit off. (Try omitting the semicolon after the close brace on the definition of struct my_struct. If you are using anything but a very recent version of g++ the error message will be a bit off.)
Something is being hidden here, but it is not the constructor for struct my_struct. What is being hidden is the name my_struct as a type identifier. You can see this in action if you remove the struct from the declaration of the variable s: Use my_struct s; instead of struct my_struct s; Without the contextual information offered by the struct keyword, the compiler now must interpret my_struct as a function name.