C Language Topics for Interview
C Language Topics for Interview
1. Pre-Processing stage ( .c .i )
• Header files expanded
• Macros will get replaced
• Specific code will be included based on conditional macro’s
• Comments will be removed
2. Compilation/Translation stage ( .i .s )
• Syntax and semantics analyses will be done
• Reports errors if any which will help programmer to fix it.
• Generates assembly code
3. Assembly stage ( .s .o )
• Assembly code converted into machine readable code.
Section Mappe
.rodata
Qualifiers
• const
Constant variable gets stored in different sections of the memory based on how you are
declaring:
auto const variable will be stored in stack section and using pointer you can modify it.
Uninitialized global const variables will be stored in .bss section and using pointers you
can modify it.
global const and Static const variable behaviour is undefined.
Strings gets stored in RODATA section.
• volatile
Assume that there is a TEMP sensor which will sense the temperature data and its driver can
read the data and write into some shared memory and there is an application which will
display the whether condition on the screen by reading the data from that same shared
memory.
These are 2 different programs and in application your program only reads this memory value
so compiler will optimizes it to get better performance but we need always updated value
from memory so to avoid optimization we will use volatile.
Memory Corruptions
Global Memory Corruption
A global data can be corrupted due to Array index overflow from the previous data or
Array index underflow from the next data.
Uninitialized pointers can also cause this issue.
To debug:
• Put a write break point and debug it.
• If no debug setup available then browse through the code to find if any previous or next data
causing this.
• Or else looking at the patterns what has written in your global location can also give you an idea.
Reasons:
• If a crash is observed in memory management primitives of the operating system, heap
corruption is a possibility. It has been observed that memory buffer corruption sometimes leads to
corruption of OS buffer linked list, causing crashes on OS code.
• If a memory corruption is observed in an allocated buffer, check the buffers in the vicinity of this
buffer to look for source of corruption.
• Corruption of buffers close to heap boundary might be due to stack overflow or stack overwrite
Stack Memory Corruption
Stack corruption is a phenomenon in which some memory locations at stack are accessed
unintentionally due to wrong coding leading to change in values at those memory locations. Since
the data corruption happens on stack memory locations, hence the term Stack Corruption.
Reasons :
• Due to bad written code, all the stack memory gets eaten up (like infinite function call)
• Accessing array out of bounds.
• An undefined/freed pointer pointing or storing a garbage stack address.
• When due to some reason, the return address of a function call gets corrupted.
In most of the compilers, some extra bytes will be allocated for any dynamic memory allocations for
book-keeping information like SIZE of the allocation, etc.
main()
{
char x[2];
For example PROCESS is an entity and its structure can be defined as below:
struct process
{ x0 x0
without struct padding With struct padding
uint32_t process_no; x1 x1
uint32_t pp_no; x2 x2
struct process *child_processes;
… x3 x3
}; y0 y0
STRUCTURE PADDING: z0 0
ARM
By default any processor access the memory word by word. z1 0
For example, on 32-bit ARM processor memory will be accessed 4 bytes (1 word) at a time.
z2 0
struct xyz z3 z0
{
int x; z1
char y; z2
float z;
}; z3
Bitfields:
Bitfields are used in the scenario where we use flag in our code and for that no need to waste lot of
memory instead we can use few bits from the byte or word. We can save the memory with bitfields.
Declaration:
struct bitfield
{
char flag1:1;
char flag2:4;
}b;
Typedef:
Using typedef we can give alias name to the existing/user defined data type to increase the
readability and simplicity.
typedef struct linkedlist list;
list *Node;
Typedef of function pointer:
typedef void (*ptr) (int, float);
UNIONS:
Unions will be used in the scenario where there are multiple members needed in the application for
a same entity but all the members are mutual exclusion.
All the members share the common memory area where highest no. of bytes will be allocated for
that union.
Ex:
union xyz
{
x0/y0 y1 y2 y3
char x;
int y;
}u;
Enumerations or enums:
Enums are mainly used to assign names to integral constants, the names make a program easy to
read and maintain.
enum week
{
Mon,
Tue,
Wed
..
}day;
Arrays of Pointers:
int *p[5] = { &x, &y, arr, &m, &n}
Pointer to Array:
int (*q)[5] = arr; Where arr is int arr[5]; array size must be 5 only.
int a[2][5] = { {1, 2, 3, 4, 5}, {11, 22, 33, 44, 55}};
int (*ptr2)[5] = a;
Below method will not give correct result using pointer to pointer
INLINE function:
Inline function must be declared with static keyword.
static inline func(void)
{
}
Recursive function
A function which calls itself is called recursive function.
Diff b/w macro’s and inline functions:
• Macro’s will be expanded in preprocessing stage and inline will be replaced in a code during
compilation stage.
• Macros will not do any type checking but inline functions will do it.
Which one is good normal function or inline function:
• Its based on the requirement.
• Normal function always creates stack frame and destroys it once done and lot of other operation
takes place which will consume lot of CPU cycles. And it won’t give better performance compared
to inline functions.
• But, with normal function call memory footprint will be less.
• Where as inline function will be expanded during compilation itself so memory footprint will be
more.
• But, it gives better performance as there is no CPU cycles wasted during execution.
Note: Formal parameter of the functions can be declared with register storage class only.
System is Little endian or big
endian
Bit-wise operations:
Set bit : n = n | ( 1 << bit )
int x = 0x1;
Reset bit: n = n & ~ ( 1 << bit )
if((char)x & 1)
printf("Little Endian\n");
Toggle bit: n = n ^ ( 1 << bit )
else
printf("Big Endian\n");
Check if kth bit is set or reset: if( n & (1 << k) != 0) then set else reset
File Operations:
14. Creating a file, reading, writing a file
15. Reading files from directory recursively and searching a particular string in it
16. Print the count of that string present in each file and total count in the directory.
Libraries
• A library in C is a collection of
object files exposed for use and
build other programs, so instead
of re-write sections of code we
bring back information that is
already existing through a library.
• There are 2 different kinds of
libraries:
• Static libraries that allows us to link
to the program during compilation
• Dynamic or shared libraries those
are preferable use when you run a
lot of programs at the same time
who are using the same library.
How to create static library?
$gcc –c file1.c file2.c
The flag '-c' we use it to stop the compilation process till compilation and assembly
stage but not done the linker phase so in this case we created a new file call
'file1.o‘ and 'file2.o‘.
• $./test
Dynamic library?
Dynamic libraries (also called shared libraries) are linked into the program in two stages.
• First, during compile time, the linker verifies that all the symbols required by the program, are either
linked into the program or in one of its dynamic libraries. However, the object files from the dynamic
library are not inserted into the executable file.
• Instead, when the program is started, a program in the system (called a dynamic loader) checks out which
shared libraries were linked with the program, loads them to memory, and attaches them to the copy of
the program in memory.
./prog
./test: error while loading shared libraries: lib_dynlib.so: cannot open shared object file: No such file or
directory
$export LD_LIBRARY_PATH=/mnt/d/Code_WS/dynamic_libs
$./prog
THANK YOU…