Tuesday, 12 July 2016

C programming tricky objective

 
C programming tricky objective type operators questions and answers with explanation for written test and interview


(1)
What will be output of the following program?
#include<stdio.h>
int main(){
    float a=0.7;d 
    if(a<0.7){
         printf("C");
    }
    else{
         printf("C++");
    }
    return 0;
}


Explanation

Output: 

Turbo C++ 3.0: c

Turbo C ++4.5: c

Linux GCC: c

Visual C++: c


Explanation: 
0.7 is double constant (Default). Its binary value is written in 64 bit.

Binary value of 0.7 = (0.1011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 )

Now here variable a is a floating point variable while 0.7 is double constant. So variable a will contain only 32 bit value i.e.
a = 0.1011 0011 0011 0011 0011 0011 0011 0011 while
0.7 = 0.1011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011....
It is obvious a < 0.7


Hide



(2)
What will be output of the following program?
        
#include<stdio.h>
int main(){
    int i=5,j;
    j=++i+++i+++i;
    printf("%d %d",i,j);
    return 0;
}

Explanation

Output: 

Turbo C++ 3.0: 8 24

Turbo C ++4.5: Compilation error

Linux GCC: Compilation error

Visual C++: Compilation error


Explanation:

Rule :- ++ is pre increment operator so in any arithmetic expression it first increment the value of variable by one in whole expression then starts assigning the final value of variable in the expression.
Compiler will treat this expression j = ++i+++i+++i; as
i = ++i + ++i + ++i;
Initial value of i = 5 due to three pre increment operator final value of i=8.
Now final value of i i.e. 8 will assigned to each variable as shown in the following figure:


So, j=8+8+8
j=24 and
i=8


Hide



(3)
What will be output of the following program?
#include<stdio.h>
int main(){
    int i=1;
    i=2+2*i++;
    printf("%d",i);
    return 0;
}

Explanation

Output: 

Turbo C++ 3.0: 5

Turbo C ++4.5: 5

Linux GCC: 5

Visual C++: 5


Explanation:
i++ i.e. when postfix increment operator is used any expression the it first assign the its value in the expression the it increments the value of variable by one. So,
i = 2 + 2 * 1
i = 4
Now i will be incremented by one so i = 4 + 1 = 5


Hide



(4)
What will be output of the following program?
#include<stdio.h>
int main(){
    int a=2,b=7,c=10;
    c=a==b;
    printf("%d",c);
    return 0;
}

Explanation

Output: 

Turbo C++ 3.0: 0

Turbo C ++4.5: 0

Linux GCC: 0

Visual C++: 0


Explanation:
== is relational operator which returns only two values.
0: If a == b is false
1: If a == b is true
Since
a=2
b=7
So, a == b is false hence b=0


Hide



(5)
What will be output of the following program?
#include<stdio.h>
void main(){
    int x;
    x=10,20,30;
    printf("%d",x);
    return 0;
}

Explanation

Output: 

Turbo C++ 3.0: 10

Turbo C ++4.5: 10

Linux GCC: 10

Visual C++: 10


Explanation :
Precedence table:
Operator
Precedence
Associative
 =
More than ,
Right to left
 ,
Least
Left to right

Since assignment operator (=) has more precedence than comma operator .So = operator will be evaluated first than comma operator. In the following expression
x = 10, 20, 30
First 10 will be assigned to x then comma operator will be evaluated.


Hide



(6)
What will be output of the following program?
#include<stdio.h>
int main(){
    int a=0,b=10;
    if(a=0){
         printf("true");
    }
    else{
         printf("false");
    }
    return 0;
}

Explanation

Output: 

Turbo C++ 3.0: false

Turbo C ++4.5: false

Linux GCC: false

Visual C++: false


Explanation:
As we know = is assignment operator not relation operator. So, a = 0 means zero will assigned to variable a. In c zero represent false and any non-zero number represents true.
So, if(0) means condition is always false hence else part will execute.


Hide



(7)
What will be output of the following program?
#include<stdio.h>
int main(){
    int a;
    a=015 + 0x71 +5;
    printf("%d",a);
    return 0;
}

Explanation

Output: 

Turbo C++ 3.0: 131

Turbo C ++4.5: 131

Linux GCC: 131

Visual C++: 131


Explanation:
015 is octal number its decimal equivalent is = 5 * 8 ^ 0 + 1 * 8 ^ 1 = 5 + 8 = 13
0x71 is hexadecimal number (0x is symbol of hexadecimal) its decimal equivalent is = 1 * 16 ^ 0 + 7 * 16 ^ 1 = 1 + 112 = 113
So, a = 13 + 113 + 5 = 131


Hide



(8)
What will be output of the following program?
#include<stdio.h>
int main(){
    printf("%d %d %d",sizeof(3.14),sizeof(3.14f),sizeof(3.14L));
    return 0;
}

Explanation

Output: 

Turbo C++ 3.0: 8 4 10

Turbo C ++4.5: 8 4 10

Linux GCC: 8 4 12

Visual C++: 8 4 8

Explanation:
3.14f is floating point constant. Its size is 4 byte. 3.14 is double constant (default). Its size is 8 byte. 3.14L is long double constant. Its size is 10 byte. sizeof() operator always return the size of data type which is written inside the(). It is keyword.



Hide



(9)
What will be output of the following program?
#include<stdio.h>
int main(){
    int x=100,y=20,z=5;
    printf("%d %d %d");
    return 0;
}

Explanation

Output:

Turbo C++ 3.0: 5 20 100

Turbo C ++4.5: 5 20 100

Linux GCC: Garbage values

Visual C++: 5 100 20

By default x, y, z are auto type data which are stored in stack in memory. Stack is LIFO data structure. So in stack first stores 100 then 20 then 5 and program counter will point top stack i.e. 5. Default value of %d in printf is data which is present in stack. So output is revere order of declaration. So output will be 5 20 100.


Hide



(10)
What will be output of the following program?
#include<stdio.h>        
int main(){
    int a=2;
    a=a++ + ~++a;
    printf("%d",a);
    return 0;
}

Explanation

Output: 

Turbo C++ 3.0: -1

Turbo C ++4.5: 0

Linux GCC: 0

Visual C++: 0


Explanation:
Same theory as question (2) and (13).


Hide



(11)
What will be output of the following program?
#include<stdio.h>
int main(){
    int a;
    a=sizeof(!5.6);
    printf("%d",a);
    return 0;
}

Explanation

Output:
Turbo C++ 3.0: 2
Turbo C ++4.5: 2
Linux GCC: 4
Visual C++: 4

Explanation:
! is negation operator it return either integer 0 or 1.
! Any operand = 0 if operand is non zero.
! Any operand = 1 if operand is zero.
So, !5.6 = 0
Since 0 is integer number and size of integer data type is two byte.


Hide



(12)
What will be output of the following program?
#include<stdio.h>
int main(){
    float a;
    (int)a= 45;
    printf("%d,a);
    return 0;
}

Explanation

Output:
Turbo C++ 3.0: Compilation error
Turbo C ++4.5: Compilation error
Linux GCC: Compilation error
Visual C++: Compilation error

Explanation:
After performing any operation on operand it always return some constant value.
(int) i.e. type casting operator is not exception for this. (int) a will return one constant value and we cannot assign any constant value to another constant value in c.

(int)a = 45; is equivalent to
3456 = 45 ( Here 3456 in any garbage value of int(a)).


Hide



(13)
What will be output of the following program?
#include<stdio.h>
int main(){
     int i=5;
     int a=++i + ++i + ++i;
     printf("%d",a);
     return 0;
}

Explanation

Output: 

Turbo C++ 3.0: 21

Turbo C ++4.5: 21

Linux GCC: 22

Visual C++: 24


Explanation:
Rule : ++ (in ++i) is pre increment operator so in any arithmetic expression it first increment the value of variable by one in whole equation up to break point then start assigning the value of variable in the equation. There are many break point operators in. For example:

(1) Declaration statement.
(2) && or operator.
(3) Comma (,) operator etc.

In the following expression:
int a=++i + ++i + ++i;

Here break point is due to declaration .It break after each increment i.e. (initial value of i=5) after first increment value 6 assign to variable i then in next increment will occur and so on.
So, a = 6 + 7 + 8;

Sunday, 10 July 2016

Good Blogs

Multiple Interview Questions




What is a kernel Panic?

It is an action taken by linux kernel when it experiences a situation from where it can't recover safely.In many cases the system may keep on running but due to security risk by fearing security breach the kernel reboots or instructs to be rebooted manually.



It can be caused due to various reasons-
1. Hardware failure
2. Software bus in the OS.
3. During booting the kernel panic can happen due to one of the reasons-
a.Kernel not correctly configured, compiled or installed.
b.Incompatibility of OS, hardware failure including RAM.
c.Missing device driver
d.Kernel unable to locate root file system
e.After booting if init process dies.


What is OOPS in Linux Kernel?

OOPS is a deviation from correct behaviour of Linux kernel which produces certain error log.
Kernel Panic is one type of OOPS. Kernel Panic doesnt allow system to continue operation while other form of OOPS ALLOW WITH COMPROMISED RELIABILITY.
When the kernel detects a problem, it prints an 
oops message and kills any offending process.



The message is used by Linux kernel engineers to debug the condition which created the oops and 
fix the programming error which caused it.
Once a system has experienced an oops, some internal resources may no longer be in service. Even if the system appears to work correctly, undesirable side effects may have resulted from the active task being killed. A kernel oops often leads on to a kernel panic once the system attempts to use resources which have been lost.
OOPS word here means the general usage of OOPs..error.

How function pointers are shared across different processes? using which IPCs?


Two processes can not share function pointers. If we want to use functions in two processes we will have to make library for those functions and we use that library in our processes.

What is a device tree in Linux?

Device tree is a data structure that describes the hardware , their layout, their parameters and other details and is passed to the kernel at boot time
 

What is bus error? what are the common causes of bus errors?


The first thing that needs to be addressed is: What is a bus? A bus is a communication unit that allows the CPU to interact with peripherals, there are different type of buses such as PCI, I2C, MDIO, Memory Buses, etc. Normally each bus would have its own protocol for transmitting data across devices, for example in the case of PCI we can have timeout errors or windows errors (data is directed to unknown addresses/devices). In memory, bus errors would refer to alignment but other errors could be attributed to physical HW problems such as faulty connections. Other type of bus errors could be single and multiple bit errors, this could be addressed by using ECC memory.
 

What is a linux kernel ? isit a process or thread?


Linux Kernel is a passive component of the OS. It does not execute, neither it is a process/thread. It itself has many subsystem and could be called with system call API/Interrupt that helps in executing the user space process in system space for more privileged access, either to I/O or any subsystem.

Why do we need two bootloaders viz. primary and secondary?

When the system starts the BootROM has no idea about the external RAM. It can only access the Internal RAM of the the CPU. So the BootROM loads the primary bootloader from the boot media (flash memory) into the internal RAM. The main job of the primary bootloader is to detect the external RAM and load the secondary bootloader into it. After this, the secondary bootloader starts its execution

How to Pass Command Line Arguments to a Kernel Module?

Generally the word command line arguments make you strike to argc/argv in C, here coming to Linux kernel modules approach is bit different and even easy to....!! lets go for a walk on this concept.

To allow arguments to be passed to your module, declare the variables that will take the values of the command line arguments as global and then use the module_param()macro, defined in linux/moduleparam.h to set the mechanism up.
Value is assigned to this variable at runtime by a command line arguments that are given like$ insmod mymodule.ko myvariable=5 while inserting/loading the module into kernel.

The variable declarations and macros should be placed at the beginning of the module for clarity.

In this post Loadable Kernel Module i have explained the basic concepts of kernel modules.

The module_param() macro takes 3 arguments: 
  • arg1 : The name of the variable.
  • arg2 : Its type
  • arg3 : Permissions for the corresponding file in sysfs. 
Example Code Snippet :

static int myint =51;
module_param(myint, int, 0);
MODULE_PARM_DESC(myint,"this is the int variable");

Integer types can be signed as usual or unsigned. 

MODULE_PARM_DESC() macro used for giving the description of variable.
Example for all the data types are given below:
static int dint;
module_param(dint, int, 0);
MODULE_PARM_DESC(dint,"this is the dynamic int variable");

static short myshort = 51;
module_param(myshort, short, 0);
MODULE_PARM_DESC(myshort,"this is the short variable");
static long int mylong = 45100;
module_param(mylong, long , 0);
MODULE_PARM_DESC(myshort,"this is the long int variable");

static char *mychar = "Smack Down";
module_param(mychar, charp, 0);
MODULE_PARM_DESC(myshort,"this is the characte string variable");

static int myarr[2] = {51,43};
static int arr_argc = 0;
module_param_array(myarr, int,&arr_argc, 0);
MODULE_PARM_DESC(myarr,"this is the array variable");

What are the Possible Task States ?


ll informations about one process is stored in struct task_struct. It includes the status, flags, priority, and many more information about one task. The task_struct of the currently running process is always available through the macro current.
 
Possible task states are:

TASK_RUNNING

(R) The process is able to run and contributes to the system load. The scheduler decides which processes really receive CPU time.
TASK_UNINTERRUPTIBLE 
(D) The process waits for some event. It will not be considered by the scheduler. The process cannot do anything while it is waiting (it cannot even be killed). This is usually used by device drivers while the process is waiting for some hardware to respond. Such a process contributes to the system load even though it will not receive CPU time; some other part of the system is considered to be working on behalf of the process.

TASK_INTERRUPTIBLE
(S) The process waits for some event as in TASK_UNINTERUPTIBLE but it can be woken up by a signal. This should be used when the action can be interrupted without side effects. A process in this state is considered asleep and does not contribute to the system load.
 
TASK_STOPPED
(T) The process is stopped by a signal (Ctrl-Z)
 
TASK_ZOMBIE
(Z) The process has exited but there are still some data structures around that could not yet be freed. The zombie will usually be freed when the parent calls wait4() to get the exit status.

What are monolithic and micro kernels and what are the differences between them?

Monolithic kernel is a single large processes running entirely in a single address space. It is a single static binary file. All kernel services exist and execute in kernel address space. The kernel can invoke functions directly. The examples of monolithic kernel based OSs are Linux, Unix.

In Microkernels, the kernel is broken down into separate processes, known as servers. Some of the servers run in kernel space and some run in user-space. All servers are kept separate and run in different address spaces.The communication in microkernels is done via message passing. The servers communicate through IPC (Interprocess Communication). Servers invoke "services" from each other by sending messages. The separation has advantage that if one server fails other server can still work efficiently. The example of microkernel based OS are Mac OS X and Windows NT.


Differences--


1 ) Monolithic kernel is much older than Microkernel. It’s used in Unix . While Idea of microkernel appeared at the end of the 1980's.
2 ) the example of os having the Monolithic kernels are UNIX , LINUX .While the os having Microkernel are QNX , L4 , HURD , initially Mach (not mac os x) later it will converted into hybrid kernel , even MINIXis not pure kernel because device driver are compiled as part of the kernel .
3 ) Monolithic kernel are faster than microkernel . While The first microkernel Mach is 50% slower than Monolithic kernel while later version like L4 only 2% or 4% slower than the Monolithic kernel .
4 ) Monolithic kernel generally are bulky . While Pure monolithic kernel has to be small in size even fit in s into processor first level cache (first generation microkernel).
5) In the Monolithic kernel device driver reside in the kernel space . While In the Microkernel device driver reside in the user space.
6 ) Since the device driver reside in the kernel space it make monolithic kernel less secure than microkernel . (Failure in the driver may lead to crash) While Microkernels are more secure than the monolithic kernel hence used in some military devices.
7 ) Monolithic kernels use signals and sockets to ensure IPC while microkernel approach uses message queues . 1 gen of microkernel poorly implemented IPC so were slow on context switches.
8 ) Adding new feature to a monolithic system means recompiling the whole kernel While You can add new feature or patches without recompiling


What is the difference between kill-6 and kill -9?

IGKILL and SIGABRT are two type of signals that are sent to process to terminate it.

SIGKILL is equivalent of "kill -9" and is used to kill zombie processes, processes that are already dead and waiting for their parent processes to reap them.
SIGABRT is equivalent of "kill -6" and is used to terminate/abort running processes.

SIGKILL signal cannot be caught or ignored and the receiving process cannot perform any clean-up upon receiving this signal.
SIGABRT signal can be caught, but it cannot be blocked.

What are the Synchronization techniques used in Linux Kernel?

For simple counter variables or for bitwise ------->atomic operations are best methods. 


atomic_t count=ATOMIC_INIT(0); or atomic_set(&count,0);
atomic_read(&count);
atomic_inc(&count);
atomic_dec(&count);
atomic_add(&count,10);
atomic_sub(&count,10);

Spinlocks are used to hold critical section for short time and can use from interrupt context and locks can not sleep,also called busy wait loops.
fully spinlocks and reader/writer spin locks are available.
spinlock_t my_spinlock;
spin_lock_init( &my_spinlock );
spin_lock( &my_spinlock );
// critical section
spin_unlock( &my_spinlock );
Spinlock variant with local CPU interrupt disable
spin_lock_irqsave( &my_spinlock, flags );
// critical section

spin_unlock_irqrestore( &my_spinlock, flags );
if your kernel thread shares data with a bottom half,
spin_lock_bh( &my_spinlock );
// critical section
spin_unlock_bh( &my_spinlock );
If we have more readers than writers for our shared resource
Reader/writer spinlock can be used

rwlock_t my_rwlock;
rwlock_init( &my_rwlock );
write_lock( &my_rwlock );
// critical section -- can read and write
write_unlock( &my_rwlock );

read_lock( &my_rwlock );

// critical section -- can read only
read_unlock( &my_rwlock );


Mutexs are used when we hold lock for longer time and if we use from process context.
DEFINE_MUTEX( my_mutex );
mutex_lock( &my_mutex );
mutex_unlock( &my_mutex );


When should one use Polling and when should one use Interrupts?

Both the mechanisms have their own pluses and minuses.

We should use interrupts when we know that our event of interest is-

1. Asynchronous
2. Important(urgent).
3. Less frequent


We should use polling when we know that our event of interest is-

1. Synchronous
2. Not so important
3. Frequent(our polling routine should encounter events more than not)

Where are macros stored in the memory?

#define func() func1(){...}

Macros aren't stored anywhere separately. They get replaced by the code even before compilation.The compiler is unaware of the presence of any macro. If the code that replaces macro is large then the program size will increase considerably due to repetition.