I have a data member in computer.h called "status" that I calculate a value for in computer.c. I would like to access this exact value and print it in a different file called display.c.
The problem is I'm not exactly sure how I can access that variable. I'm not allowed to change the parameters of display_status() and I'm assuming creating a new computer_data struct to access the status member in that function will just create a new local variable and won't work.
I'm not exactly sure how I can access the value of computer_data->status in display.c and would appreciate any help. Would I create a getter function for status specifically or something?
computer.h
struct computer_data {
struct param *status;
}
computer.c
static void computer_assign_status(){
struct computer_data *computer = computer_get_data();
computer->status = calculateStat();
}
display.c
#include "computer.h"
void display_status(){
struct computer_data *computer = computer_get_data();
printf("computer->status: %d /n", computer->status);
}
Note: Also computer_get_data() as a function is defined as "struct computer_data *computer_get_data()"
Using a get function is a good start. You just have to make it known in the other file.
In computer.h add a declaration:
struct computer_data {
struct param *status;
}
struct computer_data *computer_get_data(void);
Then you can use it in display.c.
But, of course for printing status you cannot use %d format specifier as it is a pointer to a struct.
Also in computer.c you have an error:
struct void computer_assign_status(){
That should just be void as return type.
Would I create a getter function for status specifically or something?
This totally depends on your needs. If you want to hide everything else that might be in that struct from a caller, then you might provide a function only returning pointer to the status part. Otherwise you can just do it as now where you return pointer to whole data struct.
None of your examples accesses any data defined in another compilation unit. BTW your examples are written sloppy: as an example struct void. Put some more effort when asking questions here
You can only access global (more precisely static storage with external linkage) variables defined in other compilation units.
in computer.h
struct computer_data {
struct param *status;
}
extern struct computer_data computer;
in computer.c
#include "computer.h"
struct computer_data computer;
void computer_assign_status(void)
{
computer.status = calculateStat();
}
in display.c
#include "computer.h"
void display_status()
{
printf("computer->status: %d /n", computer.status);
}
In display.c do:
extern struct computer_data * computer = computer_get_data()
instead.
This works because with the extern keyword the compiler you're using will be forced to look for the variable in an external file.
Related
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.
Context
We have three files:
module.h: it holds the declaration of a structure,
module.c: it holds the definition of the structure,
main.c: it holds an instance of the structure.
The goal is to use a structure in main.c by using an API (module.h) and not directly by manipulating the structure members. It is why the definition of the structure is in module.c and not in module.h.
Code
module.h
#ifndef MODULE_H
#define MODULE_H
typedef struct test_struct test_struct;
void initialize_test_struct(int a, int b, test_struct * test_struct_handler);
#endif
module.c
#include "module.h"
struct test_struct
{
int a;
int b;
};
void initialize_test_struct(int a, int b, test_struct * test_struct_handler)
{
test_struct_handler->a = a;
test_struct_handler->b = b;
}
main.c
#include "module.h"
int main(void)
{
test_struct my_struct; // <- GCC error here
test_struct * my_struct_handler = &my_struct;
initialize_test_struct(1, 2, my_struct_handler);
return 0;
}
Problem
If we compile those files with GCC, we will get the following error:
main.c:7:17: error: storage size of ‘my_struct’ isn’t known
Question
How can we force to use an API and so forbid to use directly a structure's members to manipulate a structure, the structure declaration and definition being in a different module than the main.c?
Since the definition of test_struct is not visible to your main function, you cannot create an instance of this object nor can you access its members. You can however create a pointer to it. So you need a function in module.c that allocates memory for an instance and returns a pointer to it. You'll also need functions to read the members.
In module.h:
test_struct *allocate_test_struct();
int get_a(test_struct *p);
int get_b(test_struct *p);
In module.c:
test_struct *allocate_test_struct()
{
test_struct *p = malloc(sizeof(test_struct));
if (!p) {
perror("malloc failed");
exit(1);
}
return p;
}
int get_a(test_struct *p)
{
return p->a;
}
int get_b(test_struct *p)
{
return p-b;
}
In main.c:
test_struct * my_struct_handler = allocate_test_struct()
initialize_test_struct(1, 2, my_struct_handler);
printf("%d\n", get_a(my_struct_handler));
printf("%d\n", get_b(my_struct_handler));
free(my_struct_handler);
You cannot instantiate a test_struct directly with only the include file because the details are not known when the C file is processed in the compiler. The language will only let you initialize pointers to objects of unknown size, not the objects themselves. The size and other details of test_struct are only known by the compiler when processing module.c
To get around this, you need to have module.c allocate data and provide a pointer to it in the initialize call. This means you have to either have the initialize function return a pointer to a newly created object (one that was either malloc'd or a global or static object), or have the function accept a test_struct **:
void initialize_test_struct(int a, int b, test_struct ** test_struct_handler)
{
*test_struct_handler = malloc(sizeof(test_struct));
//Do rest of init. You should also check return value of malloc
}
//Alternatively
test_struct * initialize_test_struct(int a, int b)
{
test_struct *temp;
temp = malloc(sizeof(test_struct);
//Init members as needed
return temp;
}
Normally in this situation the typedef is for a pointer to the opaque structure, and named to indicate that it's not the struct itself - 'typedef struct test_struct* test_struct_handle' could be appropriate, as the struct name itself is rather useless to users of the module (except to make pointers).
It's also good practice to:
Have accessor functions if you need them (which you do for your main file - see dbush's answer)
Have a 'de-init'/'free' function. The user does not necessarily know that malloc was used, and having a de-init function will make it possible to hide more implementation details.
First, what is it that you think clients of your library want to do that your API doesn’t support, and they’ll be tempted to manipulate the fields of your structure to accomplish? Consider extending the API.
One option is to force client code to get its structures from your factory function, rather than allocate them itself.
Another is to create a phony definition, perhaps containing only an array of char to establish a minimum size and alignment, so that the client code knows just enough to allocate an array of them, and the library module itself can cast the pointer and twiddle the bits.
Another is to put the definition in the header and add a comment saying that the fields are internal implementation details that might change.
Another is to port to an object-oriented language.
If we compile those files with GCC, we will get the following error:
main.c:7:17: error: storage size of ‘my_struct’ isn’t known
The reason why structures are inside the header files in the first place is so that the user source (here main.c) can access its members...
Your compiler does not know the address of the definition-less struct typedef struct test_struct test_struct; and so &my_struct won't give you its address!
And without an address, you can not get the size of any variable!
Explanation:
test_struct my_struct;
Here, you make a variable of an incomplete type and hence is not valid and doesn't have an address since its members are inaccessible...
test_struct * my_struct_handler = &my_struct;
And here you pass the address of my_struct which unnotably is not possible to gain (The structure is definition-less inside the header and the source is compiled so it can't be accessed either)...
So you use pointers in this case so that a temporary address can be assigned to the incomplete type:
/* Don't forget to change to
* 'void initialize_test_struct(int a, int b, test_struct ** test_struct_handler)'
* in the header file!
*/
void initialize_test_struct(int a, int b, test_struct ** test_struct_handler)
{
// Allocate an undefined address to the pointer...
*test_struct_handler = malloc(sizeof(test_struct));
(*test_struct_handler)->a = a;
(*test_struct_handler)->b = b;
}
// The declarations have to be present inside the headers as well...
// A function that returns the pointer to the variables a and b respectively...
// These functions can readily change their values while returning them...
int * get_a_ref(test_struct * test_struct_handler)
{
return &test_struct_handler->a;
}
int * get_b_ref(test_struct * test_struct_handler)
{
return &test_struct_handler->b;
}
and use it in main like this:
#include <stdio.h>
#include "module.h"
int main(void)
{
test_struct * my_struct_handler;
// Here a address is malloc'd to the pointer and the value is assigned to it...
initialize_test_struct(1, 2, &my_struct_handler);
// Will change the value of 'a' and similar for b as well...
// *get_a_ref(my_struct_handler) = 10;
printf("%d\n", *get_a_ref(my_struct_handler));
printf("%d\n", *get_b_ref(my_struct_handler));
return 0;
}
Just to remind you about the magic (and obscurity) of typedefs...
The following link says that structs defined in main don't have the scope to be called by functions because they are local so you should define your structs globally. However with variables, it's preferred to declare variables locally and pass to functions with pointers instead of declaring global variables.
Is there a way in pure C using pointers etc to pass a struct defined in main to a function? If you don't mind, please use the example program to demonstrate the method. Thanks.
where to declare structures, inside main() or outside main()?
This code works but is not what I want. I want to define the structure within main. Is this possible?
#include <stdio.h>
#include <SDL2/SDL.h>
void function();
struct hexColour
{
Uint32 red;
}hc;
int main(void)
{
hc.red = 0xFFFF0000;
function(hc);
return 0;
}
void function(struct hexColour hc)
{
printf("red is %x\n", hc.red);
}
What I want is:
int main(void)
{
struct hexColour
{
Uint32 red;
}hc;
hc.red = 0xFFFF0000;
function(hc);
return 0;
}
First of all you should really use proper prototypes that matched the function definitions.
Secondly, your example do pass a structure into the local variable hc in the function.
When function is running there are two distinct and separate structures in memory: The one in the main function, and the local in the function function.
To cover my bases, here are two answers for two other question that maybe is asked:
You want to define the structure itself inside the main function, and then be able to use it in other functions.
Something like
int main(void)
{
struct hexColor
{
uint32_t white;
// Other members omitted
};
struct hexColour hc;
hc.white = 0xff;
func(hc); // Assume declaration exist
}
void func(struct hexColour my_colour)
{
printf("White is %u\n", my_colour.white);
}
This is not possible. The structure hexColour is defined inside the main function only. No other function can use that structure. It doesn't matter if you pass a pointer or not, the structure hexColour still will only exist inside the main function only.
Emulate pass-by-reference by passing a pointer to a structure object. Like
struct hexColor
{
uint32_t white;
// Other members omitted
};
int main(void)
{
struct hexColour hc;
hc.white = 0xff;
// Assume declaration of function exists
func(&hc); // Emulate pass-by-reference by passing a pointer to a variable
}
void func(struct hexColour *colourPointer)
{
colourPointer->white = 0x00;
}
This is possible, because then the structure hexColour exists outside the main function, in the global scope. All functions declared and defined after the structure definition may use the structure and its members.
If you pass by value a copy is made (expensive, modifications are not reflected outside). If you want to pass a pointer to a struct just go with, but this doesn't mean you are passing a struct by reference (C doesn't have references), you are passing a pointer to a struct by value instead.
void function(struct hexColour* hc) {
printf("red is %x", hc->red);
}
int main() {
...
functon(&hc);
...
}
See:
Signature of the function changes from struct hexColor to struct hexColor* so that you are passing a pointer (by value)
To access field of the struct when dealing with pointers you use -> instead that .
You need to take the address to the struct when invoking the function, function(hc) becomes function(&hc)
Now since you are passing the address the the struct any modification is done to the real value.
You seem to have understood your linked question and its answers incompletely. You write,
The following link says that structs defined in main don't have the
scope to be called by functions because they are local so you should
define your structs globally.
The ambiguity here is between struct types, such as your struct hexColour, and objects having those types, such as your hc. Both struct types and struct objects should be declared so that they are in scope at all the places where they are needed, but that plays out differently for these two different kinds of entities and in various different situations.
However with variables, it's preferred to declare variables locally
and pass by reference instead of declaring global variables.
It is usually best to use block-scope variables instead of file-scope variables, yes, but C has only pass by value, not pass by reference. There are plenty of circumstances where it is advantageous to pass pointers (by value) instead of the objects to which they point, and this is close to pass by reference, but there is certainly no rule or general practice that passing pointers is universally better than passing the objects to which they point.
Is there
a way in pure C using pointers etc to pass a local struct to a
function?
Both the caller and the callee have to agree about the type of each argument, and there are many ways to achieve this. But there are some conventions that have grown up along with C for how to approach problems such as these in an effective way. Large among them is this:
Any function and any non-builtin type that is to be used in multiple translation units should be declared in a header file, and that header included in every translation unit that needs it.
That's a generalization of the rule you couched in terms of "global" definitions. Example:
colour.h
#ifndef COLOUR_H
#define COLOUR_H
struct hexColour {
Uint32 white;
Uint32 black;
Uint32 red;
Uint32 pink;
Uint32 grey;
}; // Note that only the type is declared here, not any objects
void function(struct hexColour hc);
#endif
Note that the declaration of type struct hexColour appears before the declaration of function function that has a parameter of that type.
You can then use those types and functions with appropriate locality, for example:
main.c:
#include "colour.h"
int main(void) {
struct hexColour hc = {
.white = 0xFFFFFFFF, .black = 0xFF000000, .red = 0xFFFF0000,
.pink = 0xFFFF9999, .grey = 0xFFA0A0A0 };
function(hc);
return 0;
}
void function(struct hexColour hc) {
printf("red is %x\n", hc.red);
}
Note that the declaration of function that forms part of its definition here matches the declaration in the header. That definition function() could as easily be defined in a different source file, instead, as long as the caller has the header file to tell it how that function is declared. You can #include coulour.h into as many different source files as needed.
Do note, however, that in this case, the struct is passed by value. That's well-defined and perfectly acceptable, but inasmuch as the function receives only a copy, it cannot effect changes to the caller's original copy. If you wanted the function to be able to do that, then you would need to pass a pointer to the struct (by value) instead of the struct itself:
void function(struct hexColour *hc) {
// ...
}
int main(void) {
// ...
function(&hc);
// ...
}
You can take a locally-defined struct and pass it to another function:
void f1(struct s);
int main()
{
struct s s1;
f1(s1);
}
You can take a locally-defined struct and pass a pointer to it to another function:
void f2(struct s *);
int main()
{
struct s s2;
f2(&s2);
}
You can return a locally-defined struct:
struct s f3()
{
struct s ret;
/* ... */
return ret;
}
You can not return a pointer to a locally-defined struct:
struct s *f4()
{
struct s ret;
/* ... */
return &ret; /* WRONG */
}
If you declare a struct within a function, it is not a global variable, so you can not refer to it in another function to which you did not pass the structure or a pointer:
void f5();
int main()
{
struct s s1;
f5();
}
void f5()
{
int x = s1.field; /* WRONG */
}
Finally, if you declare the struct type itself inside a function, you end up with a struct which you can't properly refer to elsewhere:
void f1(struct s);
int main()
{
struct s { int a, b; } s1;
f1(s1);
}
void f1(struct s arg) /* error: this struct s might not be the same as the previous one */
{
int x = arg.b; /* error: compiler might not know that struct s contains a and b */
}
Looked at the previous answers. Suggest you wrap your mind around the 'C' difference between a declaration and a definition. Note that earlier versions of 'C' would NOT allow passing a copy of a structure on the stack, only a pointer to a struct..
this error seems very easy to fix but i've been trying and have no clue.
So i have three files:
symtable.h:
typedef struct symbolTable *SymTable_T;
symtablelist.c:
#include "symtable.h"
struct Node{
char* key;
void* value;
struct Node* next;
};
struct symbolTable{
struct Node* head;
int length;
};
SymTable_T SymTable_new(void){
/* code */
}
And main.c:
#include "symtable.h"
int main(int argc, const char * argv[]) {
// insert code here...
SymTable_T emptyTable = SymTable_new();
emptyTable->length = 3; <------- ERROR
return 0;
}
I'm getting error: Incomplete definition of type "struct symbolTable"
Can anyone please give me a hint?
The reason i declare my struct in my source file is that i will have another implementation for the header file. so is there another way to fix my bug beside moving my struct declaration?
You can't access the members directly with an opaque pointer - if you keep the implementation in a separate source file, you'll have to access all the members via your interface, and not directly mess with the struct.
For instance, add this to symtable.h:
void SymTable_set_length(SymTable_T table, int len);
this to symtablelist.c:
void SymTable_set_length(SymTable_T table, int len)
{
table->length = len;
}
and in main.c change this:
emptyTable->length = 3;
to this:
SymTable_set_length(emptyTable, 3);
although in this specific case passing the length as an argument to SymTable_new() is an obviously superior solution. Even more superior is not letting the user set the length of a linked list data structure at all - the length is the number of items in it, and it is what it is. It would make no sense to, for instance, add three items to the list, and then allow main.c to set the length to 2. symtablelist.c can calculate and store the length privately, and main.c can find out what the length is, but it doesn't make much sense for main.c to be able to set the length directly. Indeed, the whole point of hiding the members of a struct behind an opaque pointer like this is precisely to prevent client code from being able to mess with the data like that and breaking the data structure's invariants in this manner.
If you want to access the members directly in main.c, then you have to have the struct definition visible, there is no alternative. This will mean either putting the struct definition in the header file (recommended) or duplicating it in main.c (highly unrecommended).
In typedef symbolTable *SymTable_T;, you refer to a non-existent type symbolTable. In C (unlike C++) the type is named struct symbolTable. (Note: the question has changed to fix this since answering it.)
There's a second problem. In main.c the code will need to be able to see the definition of struct symbolTable for you to be able to refer to fields of emptyTable. At the moment, the definition is hidden in a .c file... it should be moved to the header.
In my library, I have an instance structure, which contains everything needed for the library, this is so you can define multiple instances of the library. The library requires the user to define their own extension, or custom variables.
This is what I tried:
Library.h
typedef struct custom_s *custom;
typedef struct {
int a;
int b;
custom customs;
} instance;
And then the user can just do:
Main.c
// User sets their own custom structure
struct custom_s {
int c;
};
int main(void) {
instance test;
test.customs.c = 1;
}
However I get the error of "Segmentation fault".
Shouldn't it be:
test.customs->c = 1
Since you type'd it in
typedef struct custom_s *custom;
and Used as
custom in the instance structure.
Which is never allocated...
typedef struct custom_s *custom;
Defines a pointer to a custom struct. In your example this is an undefined pointer that is never allocated, so a segmentation fault occurs when you try to access it.
One side effect of opaque structures is that the size is unknown to client code. This means that you must create your own functions for allocating/creating them.
Make something like:
instance test;
test.customs = customs_create();
test.customs.c = 1;