It's certainly possible to do object oriented programming in C. Remember that e.g. the first C++ compiler was actually a C++ to C transpiler, the Python VM is written in C etc. The thing that sets so called OOP languages apart from other is better support for these constructs, for instance in syntax.
One common way to provide abstraction is function pointers. Look at the struct from the Linux kernel source below (from include/linux/virtio.h).
/**
* virtio_driver - operations for a virtio I/O driver
* @driver: underlying device driver (populate name and owner).
* @id_table: the ids serviced by this driver.
* @feature_table: an array of feature numbers supported by this driver.
* @feature_table_size: number of entries in the feature table array.
* @probe: the function to call when a device is found. Returns 0 or -errno.
* @remove: the function to call when a device is removed.
* @config_changed: optional function to call when the device configuration
* changes; may be called in interrupt context.
*/
struct virtio_driver {
struct device_driver driver;
const struct virtio_device_id *id_table;
const unsigned int *feature_table;
unsigned int feature_table_size;
int (*probe)(struct virtio_device *dev);
void (*scan)(struct virtio_device *dev);
void (*remove)(struct virtio_device *dev);
void (*config_changed)(struct virtio_device *dev);
#ifdef CONFIG_PM
int (*freeze)(struct virtio_device *dev);
int (*restore)(struct virtio_device *dev);
#endif
};
probe
, scan
, remove
etcetera are all function pointers that an I/O driver sets themselves. The kernel can then call these functions for any I/O driver without the need to know anything about the device. This is an example of abstraction in C. See this article to read more about this particular example.
Another form of data abstraction is opaque pointers. An opaque data type is declared in a header file, but the definition is never exposed. Code that doesn't know the definition of the type can never access it's value, only use pointers to it. See Opaque data type and Opaque pointer on Wikipedia.
An example of an opaque data type you've probably encountered is FILE
from stdio.h. The same interface is used on all operating systems, although the actual data a FILE *
points to is different. You can get a FILE *
by calling fopen
and manipulate it with a range of other function calls, but you may not see the data it points to.
To learn more about object oriented programming in C I recommend the free online book Object Oriented Programming in ANSI-C. Check out this Dr Dobbs article. Related questions: Object orientation in C and Can you write object oriented code in C?.