Can I use getters and setters in pure C instead of using extern variables?
First of all, don't listen to anyone saying "there is no object-orientation in language x" because they have truly not understood that OO is a program design method, completely apart from language syntax.
Some languages have elegant ways to implement OO, some have not. Yet it is possible to write an object-oriented program in any language, for example in C. Similarly, your program will not automagically get a proper OO design just because you wrote it in Java, or because you used certain language keywords.
The way you implement private encapsulation in C is a bit more crude than in languages with OO support, but it does like this:
// module.h
void set_x (int n);
int get_x (void);
// module.c
static int x; // private variable
void set_x (int n)
{
x = n;
}
int get_x (void)
{
return x;
}
// main.c
#include "module.h"
int main (void)
{
set_x(5);
printf("%d", get_x());
}
Can call it "class" or "ADT" or "code module" as you prefer.
This is how every reasonable C program out there is written. And has been written for the past 30-40 years or so, as long as program design has existed. If you say there are no setters/getters in a C program, then that is because you have no experience of using C.
EDIT: For completeness, the thread-safe, multi-instance version of the above is also possible using "opaque type", see How to do private encapsulation in C?
typedef struct engine_t engine_t;
, and then only define it in the c file. That way the caller will have access to the struct declaration (type name) but not the definition (contents). –
Dravidian struct engine_t;
to get an incomplete type. The typedef is there so you don't have to type out struct
all over the place, which is particularly confusing to the caller when you use opaque type and there is no struct definition to be found. –
Dravidian Yes, it's very much possible and sometimes even useful. C supports opaque types:
struct Context;
C code compiled with only this declaration in scope can not access any hypothetical members of the struct, and can't use value of type Context
either. But it can still handle pointers to Context
values, so functions like these are possible:
Context *make_context(...);
int context_get_foo(Context *);
void context_set_foo(Context *, int);
This pattern insulates the client C code from any changes to the size or internal layout of Context
. Note that this is a stronger guarantee than simply declaring but not documenting the members: Even if the programmers duly ignore the undocumented members, by-value use of the struct is permitted (and will certainly slip in), and now the code has to be recompiled when the size changes. In other words, opaque types only handled through pointers give greater ABI stability.
extern
). But I wouldn't call it a "simplified way" because it's a quite different tool, in the same way static
members in Java are not "simplified" instance members. –
Dulcie extern
global variables is very bad practice and considered "spaghetti coding". There is in fact never any reason to use the extern keyword in C. –
Dravidian Another approach is by using a global variable and inline functions:
// module.h
inline void set_x (int n) {extern int x; x = n;}
inline int get_x (void) {extern int x; return x;}
// module.c
int x; // global variable
// main.c
#include "module.h"
int main (void)
{
set_x(5);
printf("%d", get_x());
}
It has two advantages:
Getters and setters become easily inlineable
It becomes clear to the compiler that getters have no side effects, which allows further optimizations and produces no warnings in cases like this one:
// warning: compound statement with side effects
if(get_x() || get_y())
Of course, a "dedicated" (read: dumb) programmer can always write extern int x;
in their code and use the variable directly. On the other hand, a "dedicated" programmer can also easily remove the static
keyword and use it anyway...
© 2022 - 2024 — McMap. All rights reserved.