Ive got the following
typedef struct{
GLfloat x;
GLfloat y;
GLfloat z;
}Vertex3D;
and I want to use a for loop. is it possible to specify which primitive you want from a struct based on its index. e.g if I wanted using the number 0 for x 1 for y and 2 for z like an array?
Thanks for all your responses. I think I will use arrays instead. Was hoping to avoid it but ow well. GC
Not legally. The structure's elements might be aligned in memory, but I highly recommend not doing it this way, it could cause many headaches later, especially if you find your struct needs additional members later.
Try instead:
typedef struct
{
GLfloat c[3];
}Vertex3D;
and
#define VERTEX_X 0
#define VERTEX_Y 1
#define VERTEX_Z 2
then access with:
Vertex3D v;
v.c[VERTEX_X] = 5.5;
You could use
((GLfloat *)&Vertex3D)[i];
but that's just ugly.
Edit: As an answer below points out, this technically might not even work. it is possible (though improbable for this particular situation) that the elements would be padded and not contiguous in memory.
No, not cleanly. You could do
Vertex3D v;
float *pv = (float*)&v;
/* use pv[0],pv[1],pv[2] */
Technically, it's undefined behavior, but in this particular case, I wouldn't expect problems on any wide-spread compiler/OS/CPU combination.
You can take advantage of the way that the struct is stored in memory, but I would advise against it. Because all of the elements are located right next to each other in memory, you could treat it as an array, which is technically an undefined behavior, but as long as everything in your struct is the same type, it shouldn't cause any issues (because then it's basically an array).
Here's a test program that I made to prove this
#include <stdio.h>
typedef struct {
int x;
int y;
int z;
} Point;
int main() {
Point test = {1, 2, 3};
printf("x: %d\ty: %d\tz: %d\n", test.x, test.y, test.z);
int *ptest = (int *) &test;
for (int i = 0; i < 3; i++)
printf("%d\n", ptest[i]);
return 0;
}
works as expected
Related
I was implementing a structure in which I needed (at runtime) to have an optional field.
So I thought about this:
//...
#include <stdlib.h>
struct test {
int x; // Must be
int y; // Optional (Must be the last field..(?))
};
int main(int argc, char **argv) {
// With the optional field
struct test *a = malloc(sizeof(*a));
a->x = 11;
a->y = 55;
// Without the optional field
struct test *b = malloc(sizeof(*b) - sizeof(int));
b->x = 22;
// ...
free(a);
free(b);
return 0;
}
Could this code do what I ask?
Possibly adding a bit field to check if there is the optional field or not.
Also, if the proposed solution works, if this were implemented for a list of multiple items (> 100000), would it be better to do it to save memory?
Could this code do what I ask?
Well, it could, but you cannot rely on that. Do not do this; it is not a way to write correct programs.
When you write b->x = 22;, the compiler is entitled to behave as if there were a whole struct test at b. You may be thinking, “I am just putting 22 in the bytes for the member x,” but the compiler may use a “store eight bytes” instruction:
Consider some architecture where memory is organized into eight-byte groups. The bus can only read and write whole eight-byte chunks.
Since there is no way to write four bytes in hardware, writing four bytes to memory requires reading eight bytes, manipulating them in processor registers to insert the desired values in four of the bytes, and writing eight bytes back to memory.
The compiler wants to optimize b->x = 22;, and it knows y has not been set yet, so it is allowed to have any value. So, instead of using an inefficient write-four-byte sequence, the compiler generates an eight-byte store that puts 22 in b->x and 0 in b->y.
Then this fails because the compiler has just written 0 to memory that might be in use for something else because it is not part of the space you allocated for b.
“If you lie to the compiler, it will get its revenge.” — Henry Spencer
What you're attempting doesn't conform to the C standard because you're attempting to use an object of type struct test that doesn't have enough memory allocated for it, even though you're only accessing the fields for which memory was allocated. It might work but you can't rely on that.
What you can do is make use of a flexible array member:
struct test {
int x;
int y[];
};
In a struct like this, sizeof(struct test) doesn't include the last member. You can use such a struct by allocating space for the struct plus as many array elements of the last member that you want. For example:
struct test *b = malloc(sizeof(*b) + sizeof(int));
b->x = 1;
b->y[0] = 2;
You'll need to use array indexing to access the last member, but this is a way to do what you want in a standard-conforming manner.
Then in the case you don't want the last member, you do this:
struct test *b = malloc(sizeof(*b));
b->x = 1;
I think your proposed solution is dangerous. Use two different structs:
struct test_x {
int x;
};
struct test_xy {
int x;
int y;
};
Either have two arrays or store a void * to either along with a discriminator (tagged pointer for instance). The other option is use a pointer for the optional element but sizeof(int *) is the same as sizeof(int) at least on my box, so that only makes things larger.
Consider a column layout if all the y members are optional, or you can sort the data so all the xy elements comes first:
struct test_column {
int *x;
int *y;
};
struct test_column t = {
.x = malloc(100000 * sizeof(int)),
.y = 0
It doesn't help you in case but unions are the standard way to two structs share memory so size of each element is
max(sizeof(test_xy), sizeof(test_x)) instead of sizeof(test_xy) + sizeof(test_x).
Finally, consider compression especially if you use the test_column format.
I'm developing a driver in C for communication and the messages exchanged don't have a fixed size. The recommendation of communication bus is to use structs for multi-topics, which is also my case.
My 1st problem: I have to keep listening for new messages, and when I get one I have to process message data (it has a delay) and still listening for new messages.
1st solution: using thread when got new messages to process data.
My 2nd problem: Data in message can have multiple data of a struct, and my communicator requires using a struct to organize this multiple values.
2nd solution: using struct hack to allocate memory dynamic size of struct.
My current problem: when I'd pass my struct as argument to the thread, or any function, I'm loosing data structure and getting wrong values.
A short test which a made is:
typedef struct test{
int size;
int value[];
} test;
void allocation(test *v){
test *aux = (test *)malloc(sizeof(test)+3*sizeof(int));
int i;
aux->value[0] = 2;
aux->size = 3;
aux->value[1] = 1;
aux->value[2] = 5;
printf("Teste1 %d\n",aux->size);
for(i=0; i < aux->size; i++){
printf("%d\n", aux->value[i]);
}
*v = *aux;
}
void cleanup(test *v){
free(v);
}
int main(int argc, char *argv[]){
test v;
int i;
allocation(&v);
printf("Teste2 %d\n",v.size);
for(i=0; i < v.size; i++){
printf("%d\n", v.value[i]);
}
//cleanup(&v);
return 0;
}
In this test I got right values in first print and wrong values in second (only v.size is giving a right value).
And my struct is a little more complex than that in test. My struct is like:
typedef struct test1{
double v1;
double v2;
} test1;
typedef struct test2{
int size;
test1 values[];
} test2;
Do you know how to fix my memory struct in that function, once I have all elements necessary to fix? Please, keep in mind that is desirable (not required) that I could also allocate multiple test2 data.
The thing here is that you assign structs with incomplete member int value[]; Though it is in principle OK to copy two structs by value (and this is actually what happens if you write *v = *aux); However, as the compiler does not know which size member value[] will take on at runtime, the "sizeof" of v as well as the size of *aux is always 4, i.e. the known size of the one int member size. Hence, only this is copied, whereas the value[]-array simply gets not copied.
A way out out this situation would be require a pointer to a pointer (i.e. allocation(test **v), such that the memory reserved can be directly assigned to it, using a pointer to struct test in main, i.e. test *vptr, and call allocation(&vptr).
If you cannot avoid passing a reverence to the value (instead of a reference to a pointer to the value), I suppose you'll have to use memcpy to transfer the contents. But this does actually not make sense, because then the receiver must provide enough space to take on the value[]-array in advance (which is not the case if you simple declare a variable of the form test v). An then the malloc and the aux would make no sense; you could directly write into object v passed by reference.
You are declaring v as non-pointer, meaning that the memory is already allocated for v when you declare it in main. Sending the reference to your allocation only copies the size correctly since it is not dynamically allocated. Correct way to do this would be to:
Declare your v as pointer
Make your allocation return test* (test* allocation())
Assign it to v in main. i.e. something like v = allocate()
And use v like a pointer from then on
EDIT: Since OP wants this to work only as arguments, best way to go about it is using double pointer. Check the following code:
typedef struct test{
int size;
int value[];
} test;
void allocation(test **v){
test *aux = (test *)malloc(sizeof(test)+3*sizeof(int));
int i;
aux->value[0] = 2;
aux->size = 3;
aux->value[1] = 1;
aux->value[2] = 5;
printf("Teste1 %d\n",aux->size);
for(i=0; i < aux->size; i++){
printf("%d\n", aux->value[i]);
}
*v = aux;
}
void cleanup(test *v){
free(v);
}
int main(int argc, char *argv[]){
test **v;
v = malloc (sizeof (test*));
int i;
allocation(v);
printf("Teste2 %d\n",(*v)->size);
for(i=0; i < (*v)->size; i++){
printf("%d\n", (*v)->value[i]);
}
//cleanup(&v);
return 0;
}
Please note that your cleanup will change too after this.
I wanted to make a struct in C that its data couldn't be accessed by anyone directly, just through gets and sets like in Object Oriented. My solution was something like:
Point.h
#ifndef POINT_H
#define POINT_H
typedef struct point Point;
Point *CreatePoint(int x, int y);
int Point_GetX(Point *point);
void Point_SetX(Point *point, int x);
int Point_GetY(Point *point);
void Point_SetY(Point *point, int y);
void DeletePoint(Point **p);
#endif /* POINT_H */
Point.c
#include "Point.h"
struct point{
int x, y;
};
Point *CreatePoint(int x, int y){
Point *p = malloc(sizeof(Point));
if (p == NULL) return NULL;
p->x = x;
p->y = y;
return p;
}
int Point_GetX(Point *point){
return point->x;
}
void Point_SetX(Point *point, int x){
point->x = x;
}
int Point_GetY(Point *point){
return point->y;
}
void Point_SetY(Point *point, int y){
point->y = y;
}
void DeletePoint(Point **p){
if (*p != NULL){
free(*p);
*p = NULL;
}
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "Point.h"
int main(){
Point *p = CreatePoint(2, 6);
if (p == NULL) return EXIT_FAILURE;
/*
p->x = 4; "error: dereferencing pointer
p->y = 9; to incomplete type"
*/
Point_SetX(p, 4);
Point_SetY(p, 9);
printf("POINT(%d,%d)", Point_GetX(p), Point_GetY(p));
DeletePoint(&p);
return EXIT_SUCCESS;
}
Of course I'd never to all this just to a simple Point, but that's the idea. I want to know what could go wrong by doing this, whether I should be doing this or not, and if it's OK to do this, if it's not a smart approach (and I should just go for c++ xD).
The reason of this is that I'm doing a little project but I may change some data structures and algorithms later on, so if I do this, I just need to change the Point.c in this case, and not every single place I'd do
point->x = new_x
for example.
Basically, am I trying to do what c++ do? Or it's OK to do this in C? Or not, there's a disadvantage? Or this is simply not what C was meant to be? haha
My solution was something like [this]
This is the classic solution in C for information hiding. The only missing thing is DestroyPoint, a function to deallocate the point structure which you allocate with malloc.
I want to know what could go wrong by doing this, whether I should be doing this or not, and if it's OK to do this.
It is a safe approach, as long as you are OK with its disadvantage, which is described below.
[is there] a disadvantage?
Yes, there is: this approach is limited to dynamic allocation of data structures the internals of which you hide. You cannot do this:
Point p; // This fails, because `Point` is a forward declaration.
int x = Point_GetX(&p);
Similarly, arrays of Points are off-limit; embedding of Points in other structs is not possible as well.
Am I trying to do what C++ does?
Not really. Your approach is similar to Objective-C, because C++ does not have a limitation of allocating objects only in the dynamic store, while Objective-C does. This limitation does not seem to create much problems for Objective-C programmers, though.
The kind of encapsulation strategy you describe is used relatively frequently in C libraries. It is perfectly fine.
Do note, however, that it is encapsulation by convention, not enforced by the language itself, as access to private members is enforced in C++. In C, although you don't provide a complete declaration of struct point, any client code could do so, enabling it to access instances' members.
how many instances of a point struct are needed?
just one or several?
in any case, the function:CreatePoint() gaves away the farm as it gave the point data to the world.
The code needs to hide the actual content of point (and its' fields) from the world.
then ONLY the accessor functions can access point.
If there needs to be multiple instances of point,
then the CreatePoint() returns some integer that can be used in other calls to the accessor functions to select the right point.
the CreatePoint function would perform something like a malloc() to obtain room for a new point.
There probably should be a function to destroy a point (mark it destroyed in a table of points?)
printf("POINT(%d,%d)", Point_GetX(&p), Point_GetY(&p));
should be:
printf("POINT(%d,%d)", Point_GetX(p), Point_GetY(p));
Example:
struct dummy
{
int var;
};
Why structures like this are used? Mostly I have seen them in some header files.
The atomic_t type is also defined like this. Can't it be defined simply using:
typedef int atomic_t;
It's more extensible.
Assume that in the future, you realize that struct dummy should contain a name field, then you can change the definition of it to:
struct dummy
{
int var;
char name[30];
};
without changing much of your application code.
Besides extensibility, this idiom also makes it syntactically impossible to do normal arithmetic on types whose meaning is such that that doesn’t make sense semantically.
E.g.:
typedef uint32_t myObject;
myObject x, y;
...
y = x + 3; // meaningless, but doesn’t produce an error.
// may later cause runtime failure.
v.s.
typedef struct { uint32_t var; } myObject;
myObject x, y;
...
y = x + 3; // syntax error.
This may seem contrived, but it is occasionally very useful.
One other use is to pass entire arrays to functions.
struct s {
int a[3];
};
void f1(int a[]) // this evaluates to a pointer, same as void f1(int *a)
{
printf("%d\n", sizeof(a));
}
void f2(struct s *obj)
{
printf("%d\n", sizeof(obj->a));
}
int main(int argc, char **argv)
{
int a[3] = {1, 2, 3};
struct s obj;
obj.a[0] = 1;
obj.a[1] = 2;
obj.a[2] = 3;
f1(a);
f2(&obj);
return 0;
}
// output
// 8
// 12
Not all things that are representable in 32 bits should be treated as numbers. Even things that have a numeric value may have semantics which would suggest that they need special treatment. Suppose, for example, that a processor has an "atomic increment" instruction but it's slower than a "normal" increment instruction. If one wants to atomically increment fnord in one place and decrement it in another, one could use:
volatile int fnord;
...
atomic_inc(&fnord);
...
atomic_dec(&fnord);
A problem with that, however, is that if one of the places that is supposed to increment fnord happens to use fnord++ rather than atomic_inc(&fnord);, the compiler will perfectly happily generate a "normal" increment instruction, and the code may work most of the time, but it could fail in hard-to-track down fashion.
Replacing the int with a structure (and defining atomic_inc inline functions to work with it) would prevent erroneous code like fnord++; from compiling. It wouldn't guard against fnord.var++; but would give a programmer a chance to examine the structure and see what the right way to increment it would be.
Mostly it is to keep compatibility, as maybe earlier the structure had additional elements.
Or as it could be intended to add other elements later.
(or even an itnernal version of the structure has more than just one member (what I realy could imagine for atomic_t-type.)
I'm trying to learn C and I've come across something weird:
struct
{
int i;
double j;
} x, y;
struct
{
int i;
double j;
} z;
Here, you can see I created two structs that are identical in their elements.
Why is it that when I try to assign x = z it will generate a compile error but x = y does not? They have the same contents, so why can't I assign them back and forth with each other, regardless?
Is there any way I can make this so I can assign x = z? Or do they simply have to be the same struct.
Can any C gurus point me in the right direction?
They have the same content, but not the same type. If they are intended to be of the same type, simply typedef x z;. If they aren't the same thing, but just happen to contain the same fields, it's better to create a separate function that will assign the fields properly.
My usual style for declaring structs in C includes the typedef, so I forgot to mention it (sorry!). Here's the syntax:
typedef struct
{
int foo;
double bar;
} x;
/* Further down, if needed */
typedef x z;
Making identically structured types the same is called "duck typing". This is done in some languages, but not in C.
The compiler does not calculate "type equivalence" between structs that may have the same structure, so as far as it is concerned, the second struct has nothing to do with the first one.
It can do x and y because they are declared at the same time.
Why are you redeclaring the struct ? You should probably typedef the struct once (e.g., in an H file) to make it an actual type, and then declare instances.
Here's a good tutorial on typedefs for structs.
struct mystruct
{
int i;
double j;
};
struct mystruct x, y;
struct mystruct z;
If you intend to copy data between them, you must declare them with the same identity. You have two declarations, it doesn't matter they are equal for the compiler, they are two different structures, and the compiler is not supposed to detect their similarity.
C differentiates structs based on name, and if they're anonymous, then different structure definitions are different.
Anyhow, classic C doesn't allow x = z when x and z are structs -- is that an ANSI or a C99 addition? Anyhow, you should instead use
#include <string.h>
memcpy(&x, &z, sizeof(x));