Is it a good practice to repeatedly use struct in C? - c

Suppose I have these two structs coming from different header files:
header_1.h
struct main_node {
struct *sec_node
}
header_2.h
struct sec_node {
int var;
}
Now I am using this both header files in main.c and the code looks something like this:
#include <stdio.h>
#include "header_1.h"
#include "header_2.h"
struct main_node *node;
void main()
{
for (int i = 0; i < 1000; i++)
printf( "%d\n", node->sec_node->var) ;
}
Let's assume, I am not using a modern optimizing compiler. I'm looping over this struct many times, would it be faster/good practice to use a temp variable here?
Is there any difference performance-wise in C?
void main()
{
int temp = node->sec_node->var;
for (int i = 0; i < 1000; i++)
printf( "%d\n", temp);
}

It's not bad, but it can be a source of optimization bottleneck. Because the compiler cannot see the definitions of external functions (like printf here, although it might know about its properties as a builtin because it's a standard function), it must assume any external function could modify any non-const object whose address it could see. As such, in your example, node or node->sec_node may have a different value before and after the call to the external function.
One way to mitigate this is with temps like you're doing, but you can also make use of the restrict keyword as a promise to the compiler that, during the lifetime of the restrict-qualified pointer, the pointed-to object will not be accessed except via pointers "based on" the restrict-qualified one. How to do this is probably outside the scope of this question.

Related

Is a struct copied when a stack-variable is initialized by a result of a function call?

Given I'll return a large struct in a function like here:
#include <stdio.h>
// this is a large struct
struct my_struct {
int x[64];
int y[64];
int z[64];
};
struct my_struct get_my_struct_from_file(const char *filename) {
int tmp1, tmp2; // some tmp. variables
struct my_struct u;
// ... load values from filename ...
return u;
}
int main() {
struct my_struct res = get_my_struct_from_file("tmp.txt"); // <-- here
printf("x[0] = %d\n", res.x[0]);
// ... print all values ...
}
At the place marked by here, do I have to assume that this large struct is copied or is it likely that the compiler does something to avoid this?
Thank you
… do I have to assume that this large struct is copied…
No, of course you do not have to make that assumption. Nobody requires you to make that assumption, and it would be unwise to adopt the statement as an assumption rather than deriving it from known information, such as compiler documentation or inspection of the generated assembly code.
In the specific code you show, it is likely good compilers will optimize so that the structure is not copied. (Testing with Apple Clang 11 confirms it does this optimization.) But that is likely overly simplified code. If a call to get_my_struct_from_file appears in a translation unit separate from its definition, the compiler will not know what get_my_struct_from_file is accessing. If the destination object, res in this example, has had its address previously passed to some other routine in some other translation unit, then the compiler cannot know that other routine did not stash the address somewhere and that get_my_struct_from_file is not using it. So the compiler would have to treat the structure returned by get_my_struct_from_file and the structure the return value is being assigned to as separate; it could not coalesce them to avoid the copy.
To ensure the compiler does what you want, simply tell it what you want it to do. Write the code so that the function puts the results directly in the structure you want to put it in:
void get_my_struct_from_file(struct my_struct *result, const char *filename)
{
…
}
...
get_my_struct_from_file(&res, "tmp.txt");
At the place marked by here, do I have to assume that this large struct is copied or is it likely that the compiler does something to avoid this?
Semantically, the structure is copied from the function's local variable to the caller's variable. These are distinct objects, and just like objects of other types, setting one structure equal to another requires copying from the representation of one to the representation of the other.
The only way to avoid a copy would be for the compiler to treat the local variable as an alias for the caller's structure, but that would be wrong in the general case. Such aliasing can easily produce observably different behavior than would occur without.
It is possible that in some specific cases, the compiler can indeed avoid the copy, but if you want to ensure that no copying happens then you should set up the wanted aliasing explicitly:
void get_my_struct_from_file(const char *filename, struct my_struct *u) {
int tmp1, tmp2; // some tmp. variables
// ... load values from filename into *u
}
int main() {
struct my_struct res = { 0 };
get_my_struct_from_file("tmp.txt", &res);
printf("x[0] = %d\n", res.x[0]);
// ... print all values ...
}

How does linking work in C with regards to opaque pointers?

So, I've been having a bit of confusion regarding linking of various things. For this question I'm going to focus on opaque pointers.
I'll illustrate my confusion with an example. Let's say I have these three files:
main.c
#include <stdio.h>
#include "obj.h" //this directive is replaced with the code in obj.h
int main()
{
myobj = make_obj();
setid(myobj, 6);
int i = getid(myobj);
printf("ID: %i\n",i);
getchar();
return 0;
}
obj.c
#include <stdlib.h>
struct obj{
int id;
};
struct obj *make_obj(void){
return calloc(1, sizeof(struct obj));
};
void setid(struct obj *o, int i){
o->id = i;
};
int getid(struct obj *o){
return o->id;
};
obj.h
struct obj;
struct obj *make_obj(void);
void setid(struct obj *o, int i);
int getid(struct obj *o);
struct obj *myobj;
Because of the preprocessor directives, these would essentially become two files:
(I know technically stdio.h and stdlib.h would have their code replace the preprocessor directives, but I didn't bother to replace them for the sake of readability)
main.c
#include <stdio.h>
//obj.h
struct obj;
struct obj *make_obj(void);
void setid(struct obj *o, int i);
int getid(struct obj *o);
struct obj *myobj;
int main()
{
myobj = make_obj();
setid(myobj, 6);
int i = getid(myobj);
printf("ID: %i\n",i);
getchar();
return 0;
}
obj.c
#include <stdlib.h>
struct obj{
int id;
};
struct obj *make_obj(void){
return calloc(1, sizeof(struct obj));
};
void setid(struct obj *o, int i){
o->id = i;
};
int getid(struct obj *o){
return o->id;
};
Now here's where I get a bit confused. If I try to make a struct obj in main.c, I get an incomplete type error, even though main.c has the declaration struct obj;.
Even if I change the code up to use extern, It sill won't compile:
main.c
#include <stdio.h>
extern struct obj;
int main()
{
struct obj myobj;
myobj.id = 5;
int i = myobj.id;
printf("ID: %i\n",i);
getchar();
return 0;
}
obj.c
#include <stdlib.h>
struct obj{
int id;
};
So far as I can tell, main.c and obj.c do not communicate structs (unlike functions or variables for some which just need a declaration in the other file).
So, main.c has no link with struct obj types, but for some reason, in the previous example, it was able to create a pointer to one just fine struct obj *myobj;. How, why? I feel like I'm missing some vital piece of information. What are the rules regarding what can or can't go from one .c file to another?
ADDENDUM
To address the possible duplicate, I must emphasize, I'm not asking what an opaque pointer is but how it functions with regards to files linking.
Converting comments into a semi-coherent answer.
The problems with the second main.c arise because it does not have the details of struct obj; it knows that the type exists, but it knows nothing about what it contains. You can create and use pointers to struct obj; you cannot dereference those pointers, not even to copy the structure, let alone access data within the structure, because it is not known how big it is. That's why you have the functions in obj.c. They provide the services you need — object allocation, release, access to and modification of the contents (except that the object release is missing; maybe free(obj); is OK, but it's best to provide a 'destructor').
Note that obj.c should include obj.h to ensure consistency between obj.c and main.c — even if you use opaque pointers.
I'm not 100% what you mean by 'ensuring consistency'; what does that entail and why is it important?
At the moment, you could have struct obj *make_obj(int initializer) { … } in obj.c, but because you don't include obj.h in obj.c, the compiler can't tell you that your code in main.c will call it without the initializer — leading to quasi-random (indeterminate) values being used to 'initialize' the structure. If you include obj.h in obj.c, the discrepancy between the declaration in the header and the definition in the source file will be reported by the compiler and the code won't compile. The code in main.c wouldn't compile either — once the header is fixed. The header files are the 'glue' that hold the system together, ensuring consistency between the function definition and the places that use the function (references). The declaration in the header ensures that they're all consistent.
Also, I thought the whole reason why pointers are type-specific was because the pointers need the size which can vary depending on the type. How can a pointer be to something of unknown size?
As to why you can have pointers to types without knowing all the details, it is an important feature of C that provides for the interworking of separately compiled modules. All pointers to structures (of any type) must have the same size and alignment requirements. You can specify that the structure type exists by simply saying struct WhatEver; where appropriate. That's usually at file scope, not inside a function; there are complex rules for defining (or possibly redefining) structure types inside functions. And you can then use pointers to that type without more information for the compiler.
Without the detailed body of the structure (struct WhatEver { … };, where the braces and the content in between them are crucial), you cannot access what's in the structure, or create variables of type struct WhatEver — but you can create pointers (struct WhatEver *ptr = NULL;). This is important for 'type safety'. Avoid void * as a universal pointer type when you can, and you usually can avoid it — not always, but usually.
Oh okay, so the obj.h in obj.c is a means of ensuring the prototype being used matches the definition, by causing an error message if they don't.
Yes.
I'm still not entirely following in terms of all pointers having the same size and alignment. Wouldn't the size and alignment of a struct be unique to that particular struct?
The structures are all different, but the pointers to them are all the same size.
And the pointers can be the same size because struct pointers can't be dereferenced, so they don't need specific sizes?
If the compiler knows the details of the structure (there's a definition of the structure type with the { … } part present), then the pointer can be dereferenced (and variables of the structure type can be defined, as well as pointers to it, of course). If the compiler doesn't know the details, you can only define (and use) pointers to the type.
Also, out of curiosity, why would one avoid void * as a universal pointer?
You avoid void * because you lose all type safety. If you have the declaration:
extern void *delicate_and_dangerous(void *vptr);
then the compiler can't complain if you write the calls:
bool *bptr = delicate_and_dangerous(stdin);
struct AnyThing *aptr = delicate_and_dangerous(argv[1]);
If you have the declaration:
extern struct SpecialCase *delicate_and_dangerous(struct UnusualDevice *udptr);
then the compiler will tell you when you call it with a wrong pointer type, such as stdin (a FILE *) or argv[1] (a char * if you're in main()), etc. or if you assign to the wrong type of pointer variable.

How to capture a struct declaration in function

I have the following c code:
struct {
short s;
int n;
} variableName;
I want to write a function to capture this variable like so
void func(MyStruct* var){
//do stuff
}
func(&variableName);
I would like to do this without providing a definition for the struct. Is there a way to capture variableName?
No, you can't pass an "anonymous" struct into a function in C. You could of course define your function to accept the arguments individually:
void func(short s, int n) { ... }
Or you can define the MyStruct structure in a place that both the function and the calling code has visibility to. Note that the whole struct is passed by value (copy) when you do that, which may be the behavior you want here (or may not be).
You may be looking for something more like a "dictionary" or "associative array" or "hash" type that many other languages provide, with arbitrary key value pairs in it. Pure C does not have a facility for this; the compiler wants to know the layout of a structure in advance.
(I'm not sure if you might be asking about a slightly more esoteric idea, which is hiding the composition of a structure and passing around an "opaque handle" out of and into an API. There are ways to structure that in C, but please say so if that's what you're talking about.)
Completely overlooked "I would like to do this without providing a definition for the struct. Is there a way to capture variableName?" in the OP, unless it was edited after. The question makes less sense now, but heres how you could normally pass a struct to a function for future readers.
#include <stdio.h>
struct StructName{
short s;
int n;
};
void func(struct StructName struct_var){
printf("Param values are: %4X %4X\n", struct_var.s & 0xFFFF, struct_var.n & 0xFFFF);
}
int main(){
struct StructName struct_var;
struct_var.s = 0xDEAD;
struct_var.n = 0xBEEF;
func(struct_var);
}
//It looks like you are trying to use the definition as a variable. Here the definition is StructName and the variable is struct_var.
this sample code outputs:
Param values are: DEAD BEEF
If you use clang or gcc, you may be able to use typeof:
struct foo {
struct {
int i;
} anon;
} foo;
void do_something(typeof(foo.anon)* member) {
member->i = 1;
}
If there is no global instance of your type, you may be able to use typeof((struct foo){}.anon).
This comes with a lot of downsides. The most obvious ones are that:
it's not standard, and it ties you to clang/gcc
it's pretty darn ugly
it might not behave as you expect anyway
For instance, structurally-equivalent anonymous types do not have the same type, so in something like this:
struct foo {
struct {
int i;
} anon1;
struct {
int i;
} anon2;
} foo;
anon1 and anon2 both have a different type, meaning that typeof one of them cannot be used to refer to both.
In the long run, you will almost certainly find that it's worth naming the structures, especially if you use them as function arguments. For instance, if you want to make your variable available from a header, I think that you'll have to work pretty hard to keep it anonymous.
Although it's not particularly pretty and not compatible with C++, C puts the name of nested declarations in the global namespace, so this is portable and it's not a very big code change to front-load:
struct {
struct not_anon {
int i;
} anon;
} foo;
void do_something(struct not_anon* member) {
member->i = 1;
}

Acessing a locally declared struct outside of it's scope

I want to write data to an array of structures. The structure itself is declared and defined inside main(). I have 3 functions that need to write, process and read the data from the array.
All I could achieve was creating a global struct declaration and then passing pointers to them.
Is it possible without making the structure declaration global?
The relevant code is posted below.
This is my struct declaration outside of main()
struct date
{
int d;
int m;
int y;
};
struct stud
{
int roll;
char name[30];
struct date dob;
int P;
int C;
int M;
float PCM;
char flag_in;
char flag_pro;
};
These are the function defintions.
void getdata(struct stud *S)
{
scanf("%d", &(S->roll));
scanf("%s", (S->name));
//Similarly for dob, p, c, m
(S->flag_in)='1';
return;
}
void process(struct stud *S)
{
if(S->flag_in=='1')
{
S->PCM=(S->P + S->C + S->M)/3;
S->flag_pro='1';
}
}
void display(struct stud *S)
{
for(int x=0; x<10; x++)
if(S[x].flag_in=='1')
{
//printing the data to the console output
}
}
These are the function calls:
getdata(&S[i]);
process(&S[x]);
display(S);
It's entirely valid to not want to expose other parts of your program to the internal structure of a type.
C is extremely well placed to do this with considerable elegance.
Call this X.h
//Declaration of X as pointing to an incomplete struct XS.
//This says there's such a thing as a struct XS but not how it is laid out or even how big it is.
//It also says X is a short-hand for a pointer to a mysterious XS structure.
typedef struct XS* X;
//Creates an X and returns a pointer to it. Remember to call destroyX(.) exactly once - later.
X createX(void);
//Does something with X and returns some number.
int doXThing(X x);
//Destroys an X. Must be called exactly once for each return value from createX().
void destroyX(X x);
This is prog.c (containing your main(.) function).
#include <stdlib.h>
#include <stdio.h>
#include "X.h"
//Now we actually define that mysterious structure.
//Other translation units will not see this.
struct XS {
int v;
} ;
//Here we have size and layout so we can actually implement it.
X createX(void){
X x=malloc(sizeof(struct XS));//Explicit allocation of 'implementation struct'.
if(x==NULL){
return NULL;//malloc(.) failed.
}
x->v=0;
return x;
}
int doXThing(X x){
return (x->v)++;
}
void destroyX(X x){
free(x);
}
int main(void) {
X x=createX();
printf("%d\n",doXThing(x));
printf("%d\n",doXThing(x));
printf("%d\n",doXThing(x));
destroyX(x);
return 0;
}
Notice that the other modules using #include "X.h" don't see the layout of the structures.
The upside is the implementation can change normally without recompilation - just re-linking.
The downside is that without access to the size and layout of X those 'using' modules need to delegate all the work to a module that does!
That means all Xs have to come of the free-store (or a static pool inside the implementing module..).
This model is really rather common and quite powerful as it allows for complete abstraction and data hiding.
If you're willing to do a load of casting you don't even need to 'reveal' the name XS.
typedef XSHandle* X;
Or even
typedef unsigned short* X; //Little used type... Illegal but works on most platforms - check your documentation of use char (bare, signed or unsigned).
But don't get led into:
typedef void* X;
In C. void* is so promiscuous in its casting you will get into trouble!
C++ however behaves far better about that.
PS: It's not normal to put the implementation in the same translation unit as main(.).
It's not wrong in a small project but it's not normal to get into quite so much abstraction in a small project.
PPS: A stated this method provides for a very high degree of OO programming. It may be of interest that Stroustrup made documented design decisions to NOT do this for all classes in C++ because it has a fixed and unavoidable overhead and he gave himself a 'zero-overhead principle' and wanted to provide a way of 'mixing' abstraction with direct access to object layout (allocation as local variable, direct access to members, inline functions,...).
I think he made the right decision as a language level decision for the intended use of C++. That doesn't make it a bad design pattern where appropriate.
What you could do is declare the struct inside the main. and pass the pointer when the functions are called:
//this code is inside main
struct stud arr[10]; // create an array for the struct
display(arr); //pass the pointer to function
since the main is called before the functions the data will not be deleted and will exist on the processing of other functions which can pass the pointer between them.
Although I suggest not to use this method if the functions are not for one purpose (change value, print, etc...). If the data struct is used as global declare it as global.
I have the impression that you are not clear on the difference between the definition of a struct type and an instance of that type.
To be able to work with a struct variable, your functions have to see the full type declaration, such that the compiler knows how the variable is structured and to access the different fields. But there is no need that they see the variable declaration as such. The variable can be accessed without problems through a pointer that you pass as argument.
If you have your structure within the main() then the scope of this structure is local to main()
Since structures are user-defined data-types it can't used as you try because this new type is just visible within the main()
So the functions which you have defined will not have visibility of the structure.
So in order to handle this the structure should be made global.
So a binary answer to your question
Is it possible without making the structure declaration global?
is NO
Is it possible without making the structure declaration global?
No, any functions needs a struct's definition to be visible (globally) for it to be useable. Otherwise, from the function's viewpoint, the invisible struct would be an undefined identifier.
Local structs will not be visible anywhere outside the function.
The more important question would be what do you save in making it local as opposed to global? One thing that comes to my mind is that compilation time might be faster since if declared global in a header where lot of TUs see it unnecessarily.

What defines an opaque type in C, and when are they necessary and/or useful?

I've seen the concept of 'opaque types' thrown around a bit but I really haven't found a succinct answer as to what defines an opaque type in C and more importantly what problems they allow us to solve with their existence. Thanks
It is the most generally used for library purpose. The main principe behind Opaque type in c is to use data though its pointer in order to hide data handling implementation. Since the implementation is hidden, you can modify the library without recompiling any program which depend on it (if the interface is respected)
eg:
version 1:
// header file
struct s;
int s_init(struct s **x);
int s_f(struct s *x);
int s_g(struct s *x);
// source file
struct s { int x; }
int s_init(struct s **x) { *x = malloc(...); }
int s_f(..) { ... }
int s_g(..) { ... }
version 2
// header file
struct s;
int s_init(struct s **x);
int s_f(struct s *x);
int s_g(struct s *x);
// source file
struct s { int y; int x; }
int s_init(struct s **x) { *x = malloc(...); }
int s_f(..) { ... }
int s_g(..) { ... }
From your program side, nothing changed! and as said previously, no need to recompile every single program which rely on it.
In my understanding, opaque types are those which allow you to hold a handle (i.e., a pointer) to an structure, but not modify or view its contents directly (if you are allowed to at all, you do so through helper functions which understand the internal structure).
Opaque types are, in part, a way to make C more object-oriented. They allow encapsulation, so that the internal details of a type can change--or be implemented differently in different platforms/situations--without the code that uses it having to change.
An opaque type is a type which is exposed in APIs via a pointer but never concretely defined.

Resources