I am a bit confused when using struct in c/c++. Traditionally, when I use struct, I usually use it as:
typedef struct Name{
int a;
};
Name var;
Although it is considered a bad practice from Linus, it's somehow common.
Yet, I wonder
struct Name{
int a;
};
Name var;
Seems to serve the same purpose, is typedef really necessary?
In fact, shouldn't it be
struct Name{
int a;
};
struct Name var;
Why is the struct from "Name" omitted? If it can always be omitted, does that mean typedef struct is totally useless?
For:
typedef struct Name{
int a;
};
Name var;
The definition should be:
typedef struct Name{
int a;
} Name;
Name var;
Otherwise you are not aliasing the type.
In C++ this doesn't make sense, when you declare struct Name you can already instantiate Name omitting the struct keyword, as you do in the second code snippet, which would not work for C. It behaves similarly to class, in this regard, you don't declare class Name var;, just Name var;.
In C I don't agree it's a bad practice, it's a user defined type, why would you always use struct if you can omit it, any programmer worthy of that name should be able to identify a user defined type, it's not rocket science. This though is opinion based. If it's bad practice we will need to revise the whole notion, not only in C++ but also C#, where class and struct keywords are always omitted when instantiating objects.
As for aliasing pointers, I completely agree, I do not like it one bit, though this can also be seen as opinion based.
So to answer your direct questions:
Seems to serve the same purpose, is typedef really necessary?
For the purpose you describe in C yes, in C++ no.
Why is the struct from "Name" omitted?
In C it cannot be ommited, unless you typedefine it, in C++ not only it can, but it should, it's not needed at all.
If it can always be omitted, does that mean typedef struct is totally useless?
As you can see, it's not useless.
Always using struct keyword while initializing a variable could be lengthy (or whatever you think). That's why there's a typedef keyword (although it have many other uses too).
You can declare a struct with typedef like this:
typedef struct{
int a;
}var;
or
struct Name{
int a;
};
typedef struct Name var;
Then use it like:
var my_age;
However, the above explanation covers only C, whereas in C++ structs are similar to classes but their members are public by default.
So, in C++ you can directly use the struct's name without typing struct keyword again n again
struct Name {
int a;
};
Name my_age;
In C and C++, rules are different. The code you show is clearly C++, it wouldn’t compile in C.
With the following definitions:
struct Foo {
/*fields*/
};
typedef struct Bar {
/*fields*/
} Baz;
in C, variable declarations struct Foo var, struct Bar var, Baz var are valid, but plain Foo var or Bar var are not. In C++ all such variable declarations are valid. Thus, C code would typically look like:
struct Foo {
/*fields*/
};
typedef struct {
/*fields*/
} Baz;
struct Foo var1;
Baz var2;
while in C++, the typical form is:
struct Foo {
/*fields*/
};
Foo var;
UPD: technically, that’s because in struct Foo {..., in C type name is struct Foo; while in C++ the name is simply Foo, and struct is only needed to declare the type, not to use it.
Related
While reading about the visitor pattern I ran into this snippet of code:
virtual void visit(class Composite *, Component*) = 0;
This is a member function, and it seems to be forward declaring the class Composite inside its parameters. I tried this with just a normal function, like so:
void accept(class A a);
for some class A that I haven't declared or defined yet and the code worked fine. Why is this allowed? How, if at all, is it different from forward declaring before the line? Has anything changed recently in the standard in regards to this?
Many people are claiming this is a leftover of C, but then why does this code compile fine in C++, but not C?
#include <stdio.h>
int process(struct A a);
struct A{
int x;
};
int process(struct A a){
return a.x;
}
int main(void)
{
struct A a = {2};
printf("%d", process(a));
return 0;
}
This is called an incomplete type, and is a concept C++ inherited from C.
Incomplete types work this way: before you've defined a class B in your code, you can use class B varname as, say, an argument in function prototypes, or use pointers to this type as class B* ptr - anywhere where no details about a type besides its name are really needed.
Actually, you can write it differently - just put a class B; (which should work as a class declaration) before you use it as an incomplete type, and then you can write B varname instead of class B varname.
Pointers to incomplete types are often used with opaque pointers, which are probably the most common use of incomplete types in C++. Opaque pointers are described well enough in the linked Wikipedia article. Put short, it is a technique that allows your API to hide an entire class implementation.
Using the incomplete type syntaxis you describe in your question, the example code from Wikipedia:
//header file:
class Handle {
public:
/* ... */
private:
struct CheshireCat; // Not defined here
CheshireCat* smile; // Handle
};
//CPP file:
struct Handle::CheshireCat {
int a;
int b;
};
can be rewritten as:
//header file:
class Handle {
public:
/* ... */
private:
struct CheshireCat* smile; // Handle
};
//CPP file:
struct CheshireCat {
int a;
int b;
};
Note this: these code snippets are not equivalent, as the former defines a type Handle::CheshireCat, while the latter has it simply as CheshireCat.
On the code you gave as an example:
In C, the reason it doesn't compile is quite simple: the struct A in the function prototype is a declaration scoped to the function prototype, and thus it is different from the struct A which is declared latter. C and C++ have slightly different rules for this specific case. If you forward-declare the struct like this: struct A; before the function prototype, it will compile in both languages!
Other notable uses of this syntaxis:
This syntaxis has an important place as part of C++'s backward compatibility with C. You see, in C, after defining or forward-declaring a struct like this: struct A {}; or struct A;, the type's actual name would be struct A. To use the name as A, you needed to use a typedef. C++ does the latter automatically, but allows you to use A both as struct A and A. Same goes for class-es union-s, and enum-s.
Actually, some argue this has a semantical importance. Consider a function with the following signature: int asdf(A *paramname). Do you know what A is just by looking at the declaration? Is it a class, struct, enum or a union? People say that a signature like that can be made clearer in such a way: int asdf(enum A *paramname). This is a nice way of writing self-documenting code.
In C, structure names were not accessible without the struct keyword:
struct Foo {};
void bar(struct Foo foo) {...}
You could get around this by using a typedef as well:
typedef struct Foo {} Foo;
void bar(Foo foo) {...}
In C++, this remains for backward compatibility. It's been logically extended, including support for the class keyword instead of struct. class Composite * is almost equivalent to just saying Composite * in this regard. It is not necessarily used as a forward declaration, just accessing the type name.
Note that it can still be used to disambiguate if necessary:
struct Foo {};
void Foo();
int main() {
Foo foo; //error: Foo refers to the function
struct Foo foo; //okay: struct Foo refers to the class
}
Now the same declaration can introduce a type name, like it does in your accept example and possibly does in the visit example. For a function at namespace scope, if the class being declared is not found, it will be declared in the namespace containing the function (see N4140 [basic.scope.pdecl]/7).
This means that the following will not compile due to the struct/union mismatch:
void foo(struct Bar bar);
union Bar;
The above code is roughly equivalent to:
struct Bar;
void foo(Bar bar);
union Bar;
When learning C++, the books always create structs as follows:
struct X{
int a;
};
X y;
X *yp; // pointer to object of X class
But I've seen some C++ code online where people instead use the following syntax:
struct X y;
struct X *yp;
Why do they add the struct in front and is there any difference between the two methods of creating objects of X class.
In C++ (as opposed to C) you can mostly just write X when X is a struct type. You still need to write struct X
for disambiguation in some rare cases, and
when X has not yet been declared.
Examples of the last point:
in a friend declaration,
as an id type for a template,
with the usual PIMPL idiom .
Example of the first point:
struct A {};
void A() {}
auto main() -> int
{
void (*f)() = &A;
//A x; // !nyet
struct A x;
}
This is a heritage from C. In C, the following code:
struct Foo
{
int a;
};
created a struct, and put its tag "Foo" in its own 'tag-namespace'
the only way to access it was to do:
struct Foo foo;
Or, more common:
typedef struct Foo Foo;
Foo foo;
However, in C++ the tag is not just placed in a separate tag-namespace, but also
in the enclosing namespace. But for backwards compatibility, it still allows you to
access it using struct Name
There is an additional use of the construct struct Name, both in C and C++
and that is a forward declaration:
struct Later;
Later is here an incomplete type, you can use it only for things that does not
need to know its size (such as creating a pointer)
The following code compiles in C++
struct foo
{
int a, b;
};
struct foo foo()
{
struct foo a;
return a;
}
int main(void) {
foo();
return 0;
}
Is it supposed to be allowed to have a struct and a function with the same name ?
Since it compiles I then go on and try to declare an object of type foo. Is there a way? It seems impossible to do :
foo a; // error: expected ‘;’ before ‘a’
foo a{}; // error: expected ‘;’ before ‘a’
foo a(); // most vexing parse would kick in any way
Yes, this is allowed we can see this by going to draft C++ standard section 3.3.10 Name hiding paragraph 2 and it says (emphasis mine):
A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.
In this case using struct in the declaration would fix your issue:
struct foo a;
Usually a bad habbit to do something like that. I would name it foo_s or whatever to distinguish it from the function. Other than that, there isn't really a way of doing it.
In C this is possible, since it requires
struct foo
instead of just
foo
as the type name (unless it is typedef'd)
Yes, you can, but it's a really bad pattern to get into.
struct foo
{
};
foo foo(foo& f)
{
return f;
}
int main()
{
struct foo f;
foo(f);
return 0;
}
See livedemo: http://ideone.com/kRK19f
The trick was to specify struct foo when we wanted to get at the type. Note that, until you create this ambiguity, it's actually not necessary to keep saying struct, this isn't C (as in the line foo foo(foo& f)).
Most developers choose a camel casing pattern, e.g they use an upper case letter to distinguish type names and a lowercase letter for a function name:
struct Foo
{
};
Foo foo(); // no ambiguity.
Back in Microsoft's prime, many Windows developers acquired the habit of prefixing struct/class definitions, the definition of a class of thing if you will, with a capital C
struct CFoo
{
};
Now, even if you want to use upper-case first letters for your function names, there is no ambiguity.
Just do it like you would in C, using:
struct foo a;
You might even initialise it like this:
struct foo a{};
struct foo a = {0};
A workaround would be using a typedef, thus avoiding any ambiguity and other difficulties:
typedef struct foo s_foo;
From The.C++.Programming.Language.Special.Edition $A.8:
To preserve C compatibility, a class and a non-class of the same name can be declared in the same
scope ($5.7). For example:
struct stat { /* ... */ };
int stat(char * name, struct stat * buf);
In this case, the plain name (stat) is the name of the non-class. The class must be referred to using
a class-key prefix .
I am wondering if a struct has the same idea as enum in c++? If someone can explain similarities/differences I will be grateful I am trying to learn.
Are struct in c++ similar to enum or classes?
In C++, a struct is essentially the same as a class, except that the default access modifiers for member variables, methods, and for base classes are all public, where in a class, the default access modifier is private.
struct is basically a class with all members public.
For instance:
struct MyNewStruct {
int myNewInt;
double myNewDouble;
};
is equivalent to:
class MyNewClass {
public:
int myNewInt;
double myNewDouble;
};
Hence, you can create a struct with constructor:
struct MyNewStruct {
int myNewInt;
double myNewDouble;
MyNewStruct(int i, double d)
: myNewInt(i), myNewDouble(d)
{}
};
An enum is for abstracting away magic numbers.
A struct is for holding a collection of different variables.
You can almost think of an enum as a stand-in for an int or char to make things more readable.
I have structure(A) and it takes another structure(B) as member.
Now i want structure C as member of A instead of B.
Both B and C are of same type
typedef struct
{
int a;
B b;
}A
typedef struct
{
int a;
}B
typedef struct
{
int a;
}C
How can i assign struct C as member instead of B. How to do typecasting
Please help
Without knowing why you want to do this, its hard to recommend a strategy. Here are a few options though.
Option 1: Use Templates. (C++ only)
template <type T>
struct A
{
int a;
T* t;
};
struct Foo
{
int a;
};
struct B : public Foo
{
};
struct C : public Foo
{
};
struct A<Foo> A_foo;
struct B;
struct C;
A_foo.t = &B; //OK! This can now take pointer to any class that extends Foo.
A_foo.t = &C; //OK!
Option 2: Make struct A contain a void* (not recommended, you will lose all type safety). (Both C/C++)
struct A
{
int a;
void* foo; // you can now assign any pointer to foo :-S
};
C and C++ are statically typed languages. You can't do it. If you declare something as apple, it will stay as apple until the end of the times.
Although they appear to be the same type (and are, in this simple case, identical) they are considered to be different types by the compiler. This makes sense for more complex cases or in C++ where the type system is more complex than in pure C.
You generally shouldn't rely on compiler tricks or hackery to do this sort of assignment. Instead, do it properly. Either directly assign fields or, to simplify code, create a helper function along these lines:
void ASetBWithC(A *a, C c) {
assert(a != NULL);
a->b.a = c.a;
}
C++ also has the assignment operator which you could overload to do your work for you (instead of creating a named helper function) but I suspect this is beyond your current comfort level.