Open In App

Use of Callbacks in Layered Architecture

Last Updated : 05 Feb, 2019
Improve
Improve
Like Article
Like
Save
Share
Report

From OSI model of network to Operating System, any daily life project is based on layered architecture. Ever thought how the abstraction between upper layers and lower layers are created?

It is all about callbacks. So, in general upper layers are created to make things simpler and easier to use (like SDKs) and lower layers are the actual layers which interact with network (for a networking based project) or system level calls (for OS based projects). So, we can directly call a function, defined (and declared also) in lower layer, from a upper layer source file and pass the data through function arguments. But, we can not just call a function of upper layer from lower layers, as that will create a circular dependency. So, here Callbacks come into picture.

Callback is the way of passing a function through it’s reference as argument of another function and calling it later by the reference.

Let’s say upperlayer.c and lowerlayer.c are a sourcefiles of upper layer and lower layer respectively. lowerlayer.h is the header file of lowerlayer.c. In the upperlayer.c, first the function reference of notify_observer() is passed to the lowerlayer.c as an argument of register_callback(). This is called registering callback in the lower layer. Now, the lower layer knows about the function reference of notify_observer(). The register_callback() function just stores the function reference into a global function pointer g_notify_ob, so that any function from the file can call notify_observer(). Now, whenever the lower layer needs to pass data to upper layer (or needs to send a notification), it just calls notify_observer() by the calling g_notify_ob().

Below is upperlayer.c




#include <stdio.h>
#include "lowerlayer.h"
  
void notify_observer()
{
    printf("Function called by callback\n");
}
  
int main()
{
    // Calling register_callback function and 
    // passing address of notify_observer as argument
    register_callback(notify_observer);  
    lowerlevelfunction();
}


This is lowerlayer.h. The highlighted line is just to denote the prototype of the callback function that will be actually passed as reference. The basic template of the prototype is like,

typedef <Function return type> (*<Name of the function pointer type>)
                      (<Type of Function arguments separated by comma>)




// Below is the prototype of the function 
// that will be actually passed by reference 
typedef void (*notify_ob)(void);
  
void register_callback(notify_ob);
  
void lowerlevelfunction();


Now this is lowerlayer.c




#include "lowerlayer.h"
#define NULL 0
  
notify_ob g_notify_ob;
  
// Callback function
void lowerlevelfunction()
    // Calling back to notify_observer
    g_notify_ob(); 
}
  
// Callback registration
void register_callback(notify_ob fun)
{
    g_notify_ob = fun;
}


If we compile and run these files like these, the output will be like this.

$gcc -c upperlayer.c
$gcc -c lowerlayer.c
$gcc -o exe upperlayer.o lowerlayer.o
$./exe

Output: Function called by callback 


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads