Thursday, September 27, 2018

An introduction to declare, initialize and access a function pointer in C

     As we know that the pointers are variables which holds the address of another variable. Many of us might have used pointers such as integer pointer, character pointer, pointer to a structure, etc. in our usual C programming. But the use of C function pointers is very occasional. In this post, we can look at the ways to declare, initialize and access the function pointers.

What is Function Pointer:
    A function pointer is a variable, which holds the address of a function. As we know that for each variable in C, one address can be associated. This address is the memory location in main memory where the value of the variable is being stored at the run time. Like variables, each function is also has an address. Functions are sequence of instructions present in a main memory. The address of each function is the address of the first instruction of that function definition.

Function's Signature:
    Each function is having a specific signature. That is, a signature of a function is defined by the number of arguments they accept and the type of those arguments and the return type.

   For example, the below two functions have the same signatures.

   void function1 (int arg1, char arg2);
   void function2 (int val1, char val2);

   The functions "function1" and "function2" has the same signatures as they match in the number and type of arguments accepted and having the matching return type.
 
   void function3 (int data1, char data2, int data3);
   void function4 (int arg1, int arg2);

   The "function3" is having the different signature than the functions "function1" and "function2" as it differs in the number of arguments accepted.  Even though "function4" is accepting two arguments, it is having different signature than the "function1" and "function2" as its 2nd argument type differs.


Why does the Signature of a function matter?
    A function pointer always points to a function with a specific signature. So, we cannot use the same function pointer to point functions with two different signatures.
    For normal pointers, using typecast we can store address of variable of one particular type into a pointer of different type. Consider the below case.

   int *ptr = NULL;
   char data='v';
   ptr = (int*)&data;

  In the above example, we are storing the address of character variable into integer pointer using typecast. But this is NOT possible with function pointers which makes it unique and different.

Function Pointer Declaration:
    The function pointer can be declared as given below.
     <return-type> (*FnPtrName) (<argtype arg1>, <argtype arg2>,....<argtyp argN>)
                                          or
     <return-type> (*FnPtrName) (void)

  In the above syntax, the return-type can be void or any valid return types. FnPtrName can be any variable name which will be used for accessing the function pointers. It can accepts any number of arguments or it can be void.

Example:
  int (*FunPtr) (int,int) = NULL;
  
  In the above example, the function pointer is named as "FunPtr" and it accepts two integers as arguments and returns integer value. This pointer is initialized to NULL during definition of that variable.
  This function pointer can be used to store the address of any functions which is matching the signature of this function pointer; i.e any functions which is accepting two integer arguments and  returns integer results.

 
 Assigning an address to a Function pointer:

    Consider the below two function prototypes.
    int add (int,int);
    int sub (int,int);


    The functions "add" and "sub" accepts two integer arguments and returns integer results. These functions having the same signature as that of the function pointer defined in the previous example. So, we can manipulate these functions using the function pointer in example.
   We can assign the address of a function to a function pointer in two ways.

    FunPtr = add; (or) FunPtr = &add;

   Both of the above initialization are valid. The starting address of those functions will be assigned to the function pointer.

Comparing Function Pointers:
    We can compare a value of the function pointer using "==" operator as given below.

     if ((FunPtr == add) ||(*FunPtr == add))   /* We can compare directly specifying the function pointer or we can compare by de-referencing the function pointer ; both are same */
        printf ("Function Pointer Pointing to add function\n");
     else if ((FunPtr == &sub) || (*FunPtr == &sub))
       printf ("Function Pointer Pointing to sub function\n");

   When we specify "add" or "&sub", the starting address of those functions  are compared with the function pointers.

Invoking Function using a function pointer:
    We can call a function using function pointer in two ways. We can directly use the name of the function pointer or we can de-reference that function pointer.

    rslt = FunPtr (10,20); (or) rslt = (*FunPtr) (10,20);


Example:
    In this example we will put together the concepts introduced above.

 #include <stdio.h>
int add (int,int);
int sub (int,int);
int main()
{
    int var1 = 10, var2 = 20, rslt = 0;

    int (*FunPtr) (int,int) = NULL;

    FunPtr = &add;

    rslt = FunPtr (var1,var2);    /* Calling function "add" using function pointer */
    printf ("Addition Result:%d\r\n",rslt);

Tuesday, September 25, 2018

Compiling a C code using GCC for 32-bit machine architecture on a 64-bit machine


    Many of us aware of the fact that the 64 bit version of machine architecture will have the backward compatibility to lower versions. An application built for 32 bit version of Linux machine can run seamlessly on 64 bit version also, but the vice versa is not true. So, if we compile a C code on 64 bit version of Linux, it cannot be executed on the 32 bit version of Linux.
    By default, GCC builds an application for the native machine architecture. So, on 64-bit machine, the GCC builds an application for 64-bit architecture. If we want an application built on a 64-bit machine to run on both 32-bit and 64-bit machines, we can achieve it using the special compilation flag of GCC.

The -m Flag:
    GCC provides a special  compilation flag "-m" to specify the machine architecture for which the application needs to be built.
    To build for 32-bit version, specify the compilation flag as "-m32", whereas for 64-bit version, use the flag "-m64".

    Note: To execute a 32-bit application on a 64-bit machine, we need to have the 32-bit version of dynamic libraries required by that application on that 64-bit machine; otherwise the application cannot be executed.

Examples:

test.c

#include <stdio.h>
int main()
{
    printf ("Welcome\r\n");
    return 0;
}

32-bit Compilation:

gcc -m32 -o 32bitExe test.c

This Command will compile the "test.c" for 32-bit machine architecture and creates the executable with the name "32bitExe".

 Running the executable, will give the below output.

./32bitExe
Welcome


64-bit Compilation:

gcc -m64 -o 64bitExe test.c

This command will compile the code "test.c" for 64-bit machine architecture and creates the executable with the name "64bitExe".

Running the executable, will give the below output.

./64bitExe
Welcome


How to identify the executable is 32-bit or 64-bit version:

    The linux command "file" can be used to identify whether an executable is of type 32-bit or 64-bit.

    Syntax: file <executable-name>

Example:
We wanted to know whether the executable name "32bitExe" is a 32-bit or 64-bit executable. 

file 32bitExe
32bitExe: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.0.0, BuildID[sha1]=0xd4f96ae7862c856df70e8aa9fe54aeb1b41992df, not stripped

As highlighted in bold above, the output of the file command clearly specifies that the executable "32bitExe" is a 32-bit version of executable.

Similarly, for the executable "64bitExe",

file 64bitExe
64bitExe: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.4.0, BuildID[sha1]=0x14a6ae7113cedf4945c25ad5b599227f85cb46ca, not stripped


Thursday, September 20, 2018

An overview of "#" operator in C - The "C" Stringizing Operator

    In this post, I am going to talk about the stringizing operator in C. We know that the symbol "#" is used in C preprocessor directives (#define statements). In addition, it has special functionality. The # is used as stringizing operator in C.This operator generates a double quoted string when it is preceded by some multi-word string. This multi-word string can have variable name, random string, numbers, etc. This operator can be used only in the macro expansions.

Sample Program:

#include <stdio.h>
#include <string.h>
#define MAXVALUE 10
#define LOG_FAILURE(x) if(x) \
                            /* Condition Met; no need to log*/; \
                        else \
                            LogFn (#x,__func__,__LINE__)

void LogFn(const char *logstr, const char *FnName,unsigned int line)
{
    printf ("LOG: FAILED CONDITION -> %s : In FUNCTION -> %s: In LINE -> %u\n",
                logstr, FnName, line);
}

int main ()
{
    int testval = 5;
    char name[] = "NAMETEST";

    LOG_FAILURE ((testval > MAXVALUE) && "Comparing testval and MAXVALUE"); // This will log the statement as the test result fails.

    testval = 15;

    LOG_FAILURE ((testval > MAXVALUE) && "Comparing testval and MAXVALUE"); // This will not be logged as the test result passes

    testval = 2;

    LOG_FAILURE ((strlen(name) > MAXVALUE) && "Comparing string length and MAXVALUE"); // This will be logged as the test result fails.

    return 0;
}


Output:

LOG: FAILED CONDITION -> (testval > MAXVALUE) && "Comparing testval and MAXVALUE" : In FUNCTION -> main: In LINE -> 20
LOG: FAILED CONDITION -> (strlen(name) > MAXVALUE) && "Comparing string length and MAXVALUE" : In FUNCTION -> main: In LINE -> 28

Expanded source code after Macro Expansion:

# 9 "stringize_oper1.c"
void LogFn(const char *logstr, const char *FnName,unsigned int line)
{
    printf ("LOG: FAILED CONDITION -> %s : In FUNCTION -> %s: In LINE -> %u\n",
                logstr, FnName, line);
}

int main ()
{
    int testval = 5;
    char name[] = "NAMETEST";

/* The macro is expanded after preprocessing; Note that the argument preceded by # has now been converted into double-quoted string */
    if((testval > 10) && "Comparing testval and MAXVALUE") ; else LogFn ("(testval > MAXVALUE) && \"Comparing testval and MAXVALUE\"",__func__,20);

    testval = 15;

Monday, July 11, 2016

Matching a pattern in a file and Deleting a set of lines before that pattern using SED and AWK

        Consider a scenario where we are having a huge number of lines in a text file. We want to do some pattern matching and need to delete that pattern matched line as well as some lines immediately preceding that line. In this case we can follow the below steps to achieve that using SED & AWK shell commands.

Step 1: Reverse the order of the lines of the file.
This reversal is required as we are going to use the “sed” to do pattern matching and deletion of lines. As “sed” doesn’t back track, once a line is processed it is done. We cannot delete the lines preceding the pattern matched line. By reversing the order of the lines, we can easily delete the lines following the pattern matched line instead of preceding lines.

Step 2: Use the “sed” to do pattern matching and to delete the required lines.
                In this operation, for each line deleted a blank line will get generated.

Step 3: Using “awk” we can remove the empty lines introduced due to the operation performed in step 2.

Step 4: Again reverse the order of the lines of the file so that we can get the original file with unwanted lines removed.


Steps
Command
Purpose of command
Step 1
tac input_file  > output_file1
Reversing the order of line in input file and redirecting the output to another file “output_file1”
Step 2
sed –e ‘/<pattern_to_match>/,+nd’ output_file1 > output_file2

Where n = number of lines to delete following the pattern matched line.
This command will delete the pattern matched line and ‘n’ number of lines following that in the file “output_file1”. The output is redirected to the file “output_file2”
Step 3
awk NF output_file2 > output_file3
This command will remove the blank lines from “output_file2” and output is getting redirected to “output_file3”
Step 4
tac output_file3 > output_file4
Reversing the order of lines in the file “output_file3” so that we can get the original file “input_file” with unwanted lines removed.



Illustrative Example:

Input File:

Objective: In this file, we need to remove the commands which are getting failed along with its failure message.

line 1

 mac-address-table static unicast 00:00:00:00:08:01 vlan 10 interface extreme-ethernet 0/10

 mac-address-table static unicast 00:00:00:00:08:02 vlan 10 interface extreme-ethernet 0/10

 mac-address-table static unicast 00:00:00:00:08:03 vlan 10 interface extreme-ethernet 0/10

 mac-address-table static unicast 00:00:00:00:08:04 vlan 10 interface extreme-ethernet 0/10

 mac-address-table static unicast 00:00:00:00:08:05 vlan 10 interface extreme-ethernet 0/10

 mac-address-table static unicast 00:00:00:00:08:06 vlan 10 interface extreme-ethernet 0/10

Thursday, May 26, 2016

How to exclude some files in "grep"


        When we are searching for a string in a list of files using "grep" command, we may want to exclude some of the files from grep. We can achieve that with the help of the "--exclude" option in the grep command.

Example:

        For example, we are having text files name x, y, z and we want to search for "string" in these files except z. Then we can exclude the file z from the grep as given below.

        grep -nir "string" * --exclude z

        This command will search for the token "string" in all the files except file "z".

Excluding Multiple Files:

       To exclude multiple files from grepping, we can specify the command,

        grep -nir "string"  * --exclude file1 --exclude file2

Thursday, April 14, 2016

How to fix the “deadcode” type coverity warnings in C code

    Coverity is a static analysis tool used to analyze and detect the defects in our coding. Coverity tool finds the logical errors also present in the code.


Deadcode:
                It is a type of error reported by the coverity tool. A part of code is marked as “dead” if that part of code is never getting executed. Please find below the illustration for the same.

Coverity “Deadcode” Example:

void SetRowStatus (int RowStatus)
{
                if ((RowStatus < 1) || (RowStatus > 6))
                {
                                return;
                }
                switch RowStatus:
                {
                                case 1:
                                                ……
                                                ……
                                                break;
                                case 2:
                                                ……
                                                ……
                                                break;
                                case 3:
                                                ……
                                                ……
                                                break;
                                case 4:
                                                ……
                                                ……
                                                break;
                                case 5:
                                                ……
                                                ……
                                                break;
                                case 6:
                                                ……
                                                ……
                                                break;
                                default:
                                                ……                         ----> DEADCODE
                                                return;

                }
                return;
}

    In the above code snippet, the "RowStatus" variable takes on the value of 1 to 6. If the "RowStatus" value does not lie in the range of 1 to 6, the function would return in the “if” check itself. So, it is deterministic that the “default” case would never get executed in the switch block of code. So, the part of code inside the “default” case will be marked as “deadcode” by the coverity tool.

Resolving DeadCode Error:
                We might think that, removing the “default” case from the switch block of code would resolve the issue. But it will lead to the compiler warning (default case is missing). So, the correct approach is given below.

void SetRowStatus (int RowStatus)
{
                if ((RowStatus < 1) || (RowStatus > 6))
                {
                                return;
                }

Tuesday, April 5, 2016

Leonardo & the SubString - HackrRank Challenge


Leonardo & the SubString:

  • In this post we will solve the programming challenge of "Leonardo & the substring" matching posted in HackrRank.

Problem Description:

Leonardo loves puzzles involving strings, but he's just found a problem that has him stumped! Help him solve the following challenge:
Given a binary string, , composed of only 's and 's, find and print the total number of substrings of  which do not contain a  or .
Input Format
The first line contains an integer, (the number of test cases). 
The  subsequent lines of test cases each contain a string, , composed only of 's and 's.
Constraints
Output Format
For each test case, print the total number of substrings of  having no consecutive zeroes or ones (i.e.: not containing  or ).