I'm new to C and I'm trying to understand the syntax for compound literals. My question is similar to Initializing a pointer to compound literals in C but I don't think that answers it. If have a struct and a type defined as a pointer to the struct like this:
typedef struct thing *thing_t;
struct thing
{
int id;
char *name;
};
Then I can create a thing_t like this:
thing_t instance = & (struct thing) {
.id = 1,
.name = "A"
};
I was wondering if there is a way to initialize a thing_t without explicitly referring to struct thing, e.g. I tried this to see if it was valid syntax:
thing_t instance = (* thing_t) {
.id = 1,
.name = "A"
};
but the compiler errors. The compiler must "know" that the thing_t type holds a pointer to a thing, but is there syntax that allows to use the two interchangably in this context?
(I don't have a particular use case for this, I'm just trying to understand how the type and the struct are related).
I was wondering if there is a way to initialize a thing_t without
explicitly referring to struct thing, e.g. I tried this to see if it
was valid syntax:
thing_t instance = (* thing_t) {
.id = 1,
.name = "A"
};
but the compiler errors. The compiler must "know" that the thing_t
type holds a pointer to a thing,
Yes, it does, though it is poor form to define a type alias that hides pointer nature, as you have done, and it is especially poor form to do so with a name that does not somehow provide a clue about that.
but is there syntax that allows to
use the two interchangably in this context?
The syntax for a compound literal includes the parenthesized type specifier. That's not a cast, it's part of the literal itself. You cannot do without it. If you want to avoid saying struct, though, then you can kill two birds with one stone by changing your type alias so that it describes the struct type itself, not a pointer to one:
typedef struct thing thing_t;
struct thing {
int id;
char *name;
};
thing_t *instance = & (thing_t) {
.id = 1,
.name = "A"
};
Not only does it work, but it's a heck of a lot clearer than your proposal. For example, the use of the & operator matches up with the clear declaration of variable instance as a pointer.
Related
#define LENGTH 6
typedef char data_t[LENGTH];
struct foo {
const data_t data;
...
}
...
void bar(data_t data) {
printf("%.6s\n", data);
struct foo myfoo = {*data};
printf("%.6s\n", foo.data);
}
I'm trying to have this struct which holds directly the data I'm interested in, sizeof(foo) == 6+the rest, not sizeof(foo) == sizeof(void*)+the rest. However I can't find a way to initialize a struct of type foo with a data_t. I think maybe I could remove the const modifier from the field and use memcpy but I like the extra safety and clarity.
I don't get any compile errors but when I run the code I get
123456
1??
so the copy didn't work properly I think.
This is for an arduino (or similar device) so I'm trying to keep it to very portable code.
Is it just not possible ?
EDIT: removing the const modifier on the data_t field doesn't seem to help.
It is possible to do this, for some cost >=0.
typedef struct
{
char c[LENGTH];
} data_t; // this struct is freely copyable
struct foo
{
const data_t data; // but this data member is not
int what;
};
void foo (char* x) {
data_t d; // declare freely copyable struct instance
memcpy(d.c, x, sizeof(d.c)); // memcpy it
struct foo foo = { d, 42 }; // initialise struct instance with const member
...
};
Some compilers (e.g. clang) are even able to optimise away the redundant copying (from x to d.c and then from d to foo.data ⇒ from x straight to foo.data). Others (gcc I'm looking at you) don't seem to be able to achieve this.
If you pass around pointers to data_t rather than straight char pointers, you won't need this additional memcpy step. OTOH in order to access the char array inside foo you need another level of member access (.data.c instead of just .data; this has no runtime cost though).
It's impossible to do it in a standard compliant way.
Due to its being const, const char data[6]; must be initialized to be usable, and it may only be initialized statically (static objects with no initializer get automatically zeroed), with a string literal, or with a brace-enclosed initializer list. You cannot initialize it with a pointer or another array.
If I were you, I would get rid of the const, document that .data shouldn't be changed post-initialization, and then use memcpy to initialize it.
(const on struct members doesn't work very well in my opinion. It effectively prevents you from being able to have initializer functions, and while C++ gets around the problem a little bit by having special language support for its constructor functions, the problem still remains if the const members are arrays).
I'm trying to add a struct to my program using this syntax:
struct foo {
char bar[] = "baz";
char qux[] = "abc";
/* and so on */
};
For some reason, I get an error on each variable declaration within the struct saying that I have to add semicolons, and seems to fall into a kind of loop with this. The suggested syntax would be something like
struct foo {
char bar[]; =; ;;;;;;/* infinite semicolons */"baz";
}
This is the first time I've had this kind of error; am I really doing something wrong, or is this just an issue with the compiler itself?
This has nothing to do with Xcode. At all.
You're getting a compiler error because you can't initialize structs like this.
The struct type definition is about types only. Assigning values to members at this point makes no sense. Maybe you meant
struct foo {
char *bar;
char *baz;
};
struct foo x = { "quirk", "foobar" };
instead?
You are doing something wrong. You cannot assign values to the members of the struct… you're in the middle of defining the data type, not an instance of it.
This will give you your struct definition and then directly declare a variable (with initialization) of its type:
struct foo {
char *bar;
char *qux;
} variable_name = {
"baz", "abc"
};
I'm trying to get my head around structs. It seems ok in theory (e.g. a very concise and clear explanation: http://www.stanford.edu/class/cs110/hws/structs.html)
But then I find this in a code I'm messing with:
static struct pci_driver ik220_driver = {
name: DRV_NAME,
id_table: ik220_tbl,
probe: ik220_init_one,
remove: ik220_remove_one,
};
What does the = operator do here?
The = initializes a struct of type pci_driver, named ik220_driver, with the specified values for fields.
You are just assigning a variable, but it's a compound type.
Work it up in parts. struct pci_driver is a type. ik220_driver is a variable name. static sets the variable scope, so the rest: = {...} is specifying the value of the variable (which in this case happens to be a struct).
please consider the following code:
typedef struct Person* PersonRef;
struct Person {
int age;
};
const PersonRef person = NULL;
void changePerson(PersonRef newPerson) {
person = newPerson;
}
For some reason, the compiler is complaining about read-only value not assignable. But the const keyword should not make the pointer const. Any ideas?
Note that
typedef int* intptr;
const intptr x;
is not the same as:
const int* x;
intptr is pointer to int. const intptr is constant pointer to int, not pointer to constant int.
so, after a typedef pointer, i can't make it const to the content anymore?
There are some ugly ways, such as gcc's typeof macro:
typedef int* intptr;
intptr dummy;
const typeof(*dummy) *x;
but, as you see, it's pointless if you know the type behind intptr.
const PersonRef person = NULL;
is
struct Person*const person= NULL;
so you are consting the pointer and not the object.
While the problem is already solved by the answers above, I do miss the reason why...
So maybe as a rule of thumb:
The const always refers to it's predecessor token.
In case there is no such, it's "consting" it's successor token instead.
This rule can really help you out for declaring a pointer to const pointers or something equally neat.
Anyway, with this in mind, it should get clear why
struct Person *const person = NULL;
declares a const pointer to a mutable struct.
Think about it, your typedef "groups" the struct Person with the pointer token *.
So, for writing
const PersonRef person = NULL;
your compiler sees something like this (pseudo-code):
const [struct Person *]person = NULL;
As there's nothing to const's left, it deklares the token to it's right struct Person * constant.
Well I think, this is the reason why I don't like hiding pointers by typedefs, while I do like typedefs as such. What about writing
typedef struct Person { ... } Person;
const Person *person; /*< const person */
Person *const pointer; /*< const pointer to mutable person */
and it should be quite clear to compilers and humans, what you're up to.
Never hide pointers behind typedefs, it is really really bad practice and will only create bugs.
One such infamous bug is that a typedef:ed pointer type that is declared as const will be treated as a "constant pointer to non-constant data", rather than "a non-constant pointer to constant data" which is what one intuitively expects. This is what happens in your program.
Solution:
typedef struct
{
int age;
} Person;
const Person* person = NULL; // non-constant pointer to constant Person
you are getting and error
error: assignment of read-only variable ‘person’
on statement
person = newPerson;
because you have declared person as const so its value is only read only ....const value can not be changed
if you are going to change that vatiable then why you are kepping it const?
remove const keyword your code will works fine
As an addition to Piotr's (accepted) answer, it's possible to avoid GCC-specific typeof:
static_assert(std::is_same<const int *, std::add_const_t<std::remove_pointer_t<intptr>> *>::value, "not same via type_traits");
static_assert(std::is_same<const int *, std::remove_reference_t<decltype(std::as_const(*intptr()))>*>::value, "not same via decltype");
By changing foo_t<T> to foo<T>::type above and/or using boost's version, it's even possible to do this in C++98, though it's only pretty since C++11.
Alternatively, use two different typedefs, which also works for cases other than plain pointers. For example, consider every container's iterator and const_iterator typedefs.
Sometimes I see code like this (I hope I remember it correctly):
typedef struct st {
int a; char b;
} *stp;
While the usual pattern that I familiar with, is:
typedef struct st {
int a; char b;
} st;
So what's the advantage in the first code example?
You probably mean this:
typedef struct ST {
/* fields omitted */
} *STP;
The asterisk is at the end of the statement. This simply means "define the type STP to be a pointer to a struct of this type". The struct tag (ST) is not needed, it's only useful if you want to be able to refer to the struct type by itself, later on.
You could also have both, like so:
typedef struct {
/* fields omitted */
} ST, *STP;
This would make it possible to use ST to refer to the struct type itself, and STP for pointers to ST.
Personally I find it a very bad practice to include the asterisk in typedefs, since it tries to encode something (the fact that the type is a pointer) into the name of the type, when C already provides its own mechanism (the asterisk) to show this. It makes it very confusing and breaks the symmetry of the asterisk, which appears both in declaration and use of pointers.
It's a habit that stems from the time when typedef names and struct tagnames were in the same namespace. See http://blogs.msdn.com/oldnewthing/archive/2008/03/26/8336829.aspx
I think you are talking about :
typedef struct{
int a;
char b;
} object, *objectPointer;
This means that (new) type objectPointer is a pointer to struct (object) defined above. Its easy to declare pointers to object struct this way. For instance,
objectPointer A = (objectPointer)malloc(sizeof(object));
A->a = 2;
Now, A is a pointer to struct object and you can access its variables as described above.
In case, objectPointer was not defined,
struct object *A = (struct object *)malloc(sizeof(object));
A->a = 2;
So, I guess objectPointer is more intuitive and easy to use.
I hope that the first code would say a compiler error ,
I see no good reason for the typedef name be different from the tag name.
Now, the reason for which the tag name needs to be typedefed if you don't want to use
struct tag v;
but
tag v;
is probably an historical one. For as long as I remember, C had typedef but I don't know if it was true when struct have been introduced (handling of typedef is a nuisance in the C grammar). In the old code I've seen, using typedef for struct isn't done, and there are things like unix
struct stat;
int stat(const char*, struct stat*);
which would break with an automatic typedef. One those are introduced, changing is quite difficult (yes, C++ has automatic typedef but C++ has special wording to handle that case of overloading and it would be yet another complication).