I have a struct vec:
struct vec {
float x, y, z;
}
And a method to do arithmetic on two vectors, in this case subtraction:
vec* sub(vec* a, vec* b) {
struct vec* new = (vec*)malloc(sizeof(struct vec));
new->x = a->x - b->x;
new->y = a->y - b->y;
new->z = a->z - b->z;
return new;
}
Behavior of arithmetic with integers, floats, etc is simple:
int - int = int
But is undefined for vec:
vec - vec = compiler errors
Is there a way to define behavior of operands on structs? Say I just want to type new = a - b, is there a way to configure it such that that line does the function sub?
This is what C++ gives you. In C, you stick with calling sub.
Another issue is the dynamic allocation, it can get clunky and means you can't work with stack varibles as easily. Couple of solutions to that, move the allocation out of the subtract
if we typedef the vec :-
typedef struct { float x, y, z;} vec;
then...
vec* subtract(vec* l, vec *r, vec *result);
you can them build a subtract ontop of this one that also mallocs if you like, but this way the subtract will work with either dynamic or stack based variables.
or by value
vec subtract(vec l, vec r);
by value is probably best for your small struct, but, it's up to you.
Related
I thought of this problem when I was learning C,I thought of two ways to initialize the structure on the heap.
typedef struct Point {
int x;
int y;
int z;
} Point;
Point *test1(int x, int y, int z) {
Point *point = (Point *) malloc(sizeof(Point));
point->x = x;
point->y = y;
point->z = z;
return point;
}
Point *test2(int x, int y, int z) {
Point *point = (Point *) malloc(sizeof(Point));
*point = (Point) {x, y, z};
return point;
}
The writing in test1 is what I usually use, but the writing in test2 seems to be more convenient. But will test2 create extra objects?
Although the structure here has only 3 members, will the number of members affect the conclusion?
Compilers will optimize both functions to identical code. See for yourself on godbolt
This is micro-optimizations. If you care about performance you first benchmark and profile then you optimize the hot spots.
There are other ways to do it, such as C99-style initialization:
Point *test3( int x, int y, int z ) {
Point * const point = (Point *) malloc(sizeof(Point));
if (point) { // Don't write through a NULL pointer!
*point = { .x = x,
.y = y,
.z = z };
}
return point;
}
This has the advantage that it will still work if the members of Point are rearranged and extended. It’s also useful for writing static single assignments.
I also tend to prefer calloc() to set all the uninitialized bits of the structure to zero. It probably makes no difference, but if it did, that’s a really annoying Heisenbug to track down.
I have a couple of questions all relating to the same code. In this code, I am trying to return the value for V, Ug1, Ug2, Vg1, and Vg2 from the "submerged_volume" function. Then, I want to use these values in the "centre_of_buoyancy" function. From that function, I want to return two values: Uc, and Vc. Finally, I want to call these functions using the header file in my main, and use the returned values from the functions for further calculations! I have not included the main body as it just has long calculations, so for the sake of space, here's a summarised version of my code:
#ifndef DATE_H_
#define DATE_H_
double submerged_volume(double L1, double L2, double Lavg, double H) {
//Boat parameters
double V1, V2;
double Ug1, Ug2, Vg1, Vg2; //lengths in U and V direction in relation to gravity
double V; //Submerged volume
//Initialising V, the value to calculate
V = 0;
//Volume Calculations
....
....
return V, Ug1, Ug2, Vg1, Vg2, V1, V2;
}
double centre_of_buoyancy(double Ug1, double Ug2, double Vg1, double Vg2, double V1, double V2);
//Calculations for Uc and Vc
.....
.....
return Uc, Vc;
}
#endif
I understand that this won't work as I can't return multiple variables. My question is, is there some way that I can do this? I'm very new to C and am not sure exactly how to use things like this!
You can define a struct holding those values, and return that from your function. (Check your C reference of choice for documentation of structs.)
BTW, you don't return anything "in a header", you only return something "from a function". And defining a function in a header file is asking for trouble. The idea is to declare the function in the header, and to define it in a source (.c) file.
Since I didn't really understand what you're trying to do, excuse me for using my own example.
Header:
#ifndef POINT_H_
#define POINT_H_
struct point_t
{
int x;
int y;
};
struct point_t move_horizontal( struct point_t point, int offset );
struct point_t move_vertical( struct point_t point, int offset );
#endif
Source:
#include "point.h"
struct point_t move_horizontal( struct point_t point, int offset )
{
point.x += offset;
return point;
}
struct point_t move_vertical( struct point_t point, int offset )
{
point.y += offset;
return point;
}
Main:
#include "point.h"
int main()
{
struct point_t some_point = { 0, 0 };
struct point_t other_point = move_horizontal( some_point, 42 );
return 0;
}
Non-sensical of course, but you might get the idea. Source and Main are two distinct compilation units, both of which include the header to know what they're talking about. The linker then puts them together, adds some runtime support, and generates your binary. (Your C book of choice should really have told you as much.)
There is a way to do this, and it's called struct. With struct, you aggregate data and look at them as a single type. That's very nice, since you can give a name to each part of the data:
struct boat_params
{
double submerged_volume;
double length_in_U1,
length_in_U2,
length_in_V1,
length_in_V2;
/* etc */
};
and then you fill this information and return it:
struct boat_params submerged_volume(double L1, double L2, double Lavg, double H) {
//Boat parameters
struct boat_params params;
//Initialising V, the value to calculate
params.submerged_volume = 0;
//Volume Calculations (params.<fields>)
....
....
return params;
}
It makes sense to create a struct for the arguments of the function too, since they are many and they all look similar (all double). Creating a struct when you have many parameters helps the users of your function (and yourself) stay sane by easily assigning values to the parameters by their name, rather than some arbitrary order.
For example:
struct boat_data
{
double L1, L2; /* of course, give better names */
double Lavg;
double H;
};
struct boat_params submerged_volume(struct boat_data boat);
and the user would do:
struct boat_data boat;
struct boat_params params;
boat.L1 = ...;
boat.L2 = ...;
....
params = submerged_volume(boat); /* look how nice this looks */
Once you learn about pointers, you can make it more efficient by passing pointers rather than copying a bulk of data:
void submerged_volume(struct boat_data *boat, struct boat_param *params);
//Initialising V, the value to calculate
params->submerged_volume = 0;
//Volume Calculations (params-><fields>)
....
....
}
and later:
struct boat_data boat;
struct boat_params params;
boat.L1 = ...;
boat.L2 = ...;
....
submerged_volume(&boat, ¶ms); /* less nice, but efficient and still short */
Typcially you would define the function prototype in the header file and the implementation in the .c file.
As #DevSolar said you could define a struct and return this from the function.
struct Boat
{
double V1, V2;
double Ug1, Ug2, Vg1, Vg2;
};
Alternatively you could pass in arguments by reference and modify the variable directly in memory through pointers.
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
I have two identical (but differently named) C structures:
typedef struct {
double x;
double y;
double z;
} CMAcceleration;
typedef struct {
double x;
double y;
double z;
} Vector3d;
Now I want to assign a CMAcceleration variable to a Vector3d variable (copying the whole struct). How can I do this?
I tried the following but get these compiler errors:
vector = acceleration; // "incompatible type"
vector = (Vector3d)acceleration; // "conversion to non-scalar type requested"
Of course I can resort to set all members individually:
vector.x = acceleration.x;
vector.y = acceleration.y;
vector.z = acceleration.z;
but that seems rather inconvenient.
What's the best solution?
That's your only solution (apart from wrapping it into a function):
vector.x = acceleration.x;
vector.y = acceleration.y;
vector.z = acceleration.z;
You could actually cast it, like this (using pointers)
Vector3d *vector = (Vector3d*) &acceleration;
but this is not in the specs and therefore the behaviour depends on the compiler, runtime and the big green space monster.
You could use a pointer to do the typecast;
vector = *((Vector3d *) &acceleration);
memcpy(&vector, &acceleration, sizeof(Vector3d));
Please note that this works only, if the physical layout of the structs in memory are identical. However, as #Oli pointed out, the compiler is not obliged to ensure this!
You use an utility function for that:
void AccelerationToVector( struct CMAcceleration* from, struct Vector3d* to )
{
to->x = from->x;
to->y = from->y;
to->z = from->z;
}
Why dont you use.
typedef CMAcceleration Vector3d;
(instead of creating a whole new structure)
in that case vector = acceleration; compiles just fine.
Another version of the utility function making use of C99:
static inline struct Vector3d AccelerationToVector(struct CMAcceleration In)
{
return (struct Vector3d){In.x, In.y, In.z};
}
With the compiler optimization turned up (e.g., -Os), this should turn into absolutely no object code when invoked.
This is achieved easily through a union:
typedef struct {
double x;
double y;
double z;
} CMAcceleration;
typedef struct {
double x;
double y;
double z;
} Vector3d;
typedef union {
CMAcceleration acceleration;
Vector3d vector;
} view;
int main() {
view v = (view) (Vector3d) {1.0, 2.0, 3.0};
CMAcceleration accel = v.acceleration;
printf("proof: %g %g %g\n", accel.x, accel.y, accel.z);
}
A safe (albeit somewhat convoluted) way to do it would be to use a union:
union { CMAcceleration a, Vector3d v } tmp = { .a = acceleration };
vector = tmp.v;
Values are reinterpreted (since C99) when the accessed member is not the last set one. In this case, we set the acceleration and then we access the vector, so the acceleration is reinterpreted.
This is the way the NSRectToCGRect function is implemented, for example.
You could create a union with pointers that way you avoid copying data.
example :
struct Ocp1SyncHeader
{
aes70::OCP1::OcaUint8 syncVal;
aes70::OCP1::Ocp1Header header;
};
struct convertToOcp1SyncHeader
{
union
{
Ocp1SyncHeader* data;
const uint8_t* src;
};
convertToOcp1SyncHeader& operator=(const uint8_t* rvalue)
{
src = (const uint8_t*)rvalue;
return *this;
}
};
** access like this:
convertToOcp1SyncHeader RecvData;
RecvData = src; // src is your block of data that you want to access
** access members like this :
RecvData.data.header
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));