snprintf and sscanf

snprintf and sscanf


Neelkanth_221$ cat sscanf.c
#include <stdio.h>

#define IFNAMSIZ  16
#define ETHER_ADDR_STR_LEN  18

void main(void)
{
    char  ifname[IFNAMSIZ + 1]               = "eth0";
    char   sta_mac_ea[ETHER_ADDR_STR_LEN]    = "11:11:11:11:12:32";
    unsigned int event_type                  = 123;

    char a[256] = {0};

    snprintf(a, sizeof(a), "%s %s %d", ifname, sta_mac_ea, event_type);

    printf("######### After snprintf ############\n");
    printf("%s\n", a);

    char  ifname_1[IFNAMSIZ + 1]             = {0};
    char   sta_mac_ea_1[ETHER_ADDR_STR_LEN]  = {0};
    unsigned int event_type_1                = 0;

    sscanf(a, "%s %s %d", ifname_1, sta_mac_ea_1, &event_type_1);

    printf("######### After sscanf ############\n");
    printf("%d\n", event_type_1);
    printf("%s\n", sta_mac_ea_1);
    printf("%s\n", ifname_1);


    return;
}


Neelkanth_221$ ./a.out

######### After snprintf ############
eth0 11:11:11:11:12:32 123
######### After sscanf ############
123
11:11:11:11:12:32
eth0

C program to copy data from structure into array and from array back into another structure

C program to copy data from structure into array and from array back into another structure


#include <stdio.h>
#include <unistd.h>
#include <string.h>

/*
 * copy a structure into array (memcpy)
 * copy an array into structure (memcpy)
 * retrieve structure's parameters
 */

struct temp {
    char a[100];
    char b[21];
    char c[32];
};

int main()
{
    char a[500];

    struct temp temp1;

    strcpy(temp1.a, "roger federer");
    strcpy(temp1.b, "rafael nadal");
    strcpy(temp1.c, "novak djokovic");

    struct temp temp2;

    memcpy(a, &temp1, sizeof(struct temp));

    memcpy(&temp2, a, sizeof(struct temp));
    printf("%s \n%s \n%s\n",  temp2.a, temp2.b, temp2.c);

    return 0;
}


Neelkanth_221$ ./a.out

roger federer
rafael nadal
novak djokovic

Complete procedure on how to use "gcov" code coverage tool in linux

#############################
How to test gcov in linux
#############################

##############################################################Step 1: Compile an image with the below flags and make sure that the process runs infinitely.##############################################################

gcc -Wall -fprofile-arcs -ftest-coverage hello.c -o hello

################################################################Step 2: Get the PID of the process that is running "infinitely" ################################################################

Neelkanth_221$ ps -elf | grep hello
0 R labuser  21036  5897 99  80   0 -  1056 -      20:53 pts/14   00:02:18 ./hello
0 S labuser  21047 20631  0  80   0 -  3989 pipe_w 20:56 pts/16   00:00:00 grep --color=auto hello

####################################################################
Step 3: Issue SIGUSR1 signal to the "pid" of the process for which
we will be running gcov.
####################################################################

kill -SIGUSR1 21055


####################################################################Step 4: hello.gcno file would be generated. do gcov <hello.gcno> to get the gcov report ####################################################################

hello.gcno
Neelkanth_221$ gcov hello.gcno
File 'hello.c'
Lines executed:93.33% of 15
Creating 'hello.c.gcov'


#####################################################################                  Sample "hello.c" code for gcov#####################################################################

/*
 * dumping gcov data at runtime - note: no error handling to keep it simple
 */
/*
 * Compile: gcc -Wall -fprofile-arcs -ftest-coverage hello.c -o hello
 * Run: ./hello &
 *      kill -s SIGUSR1 `pidof hello`
 *
 */
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

static unsigned long long i = 0;
void __gcov_flush(void); /* check in gcc sources gcc/gcov-io.h for the prototype */

void my_handler(int signum)
{
    printf("received signal\n");
    printf("%llu\n", i);
    __gcov_flush(); /* dump coverage data on receiving SIGUSR1 */
}

int main(int argc, char **argv)
{
    struct sigaction new_action, old_action;
    int n;

    /* setup signal hander */
    new_action.sa_handler = my_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;

    sigaction(SIGUSR1, NULL, &old_action);
    if (old_action.sa_handler != SIG_IGN)
        sigaction (SIGUSR1, &new_action, NULL);

    /* infinite loop - to exemplify dumping coverage data while program runs */
    for(n = 0; ; n++) {
        i++;

        if (0) {
            printf("roger federer\n");
        }
        if (0) {
            printf("roger federer\n");
        }
        if (0) {
            printf("roger federer\n");
        }
        if (0) {
            printf("roger federer\n");
        }
        if (0) {
            printf("roger federer\n");
        }

    }

}


The Four Stages of Compiling a C Program

Compiling a C program is a multi-stage process. At an overview level, the process can be split into four separate stages: Preprocessing, compilation, assembly, and linking.


/*
 * "Hello, World!": A classic.
 */

#include <stdio.h>

int
main(void)
{
puts("Hello, World!");
return 0;
}

Preprocessing

The first stage of compilation is called preprocessing. In this stage, lines starting with a # character are interpreted by the preprocessor as preprocessor commands. These commands form a simple macro language with its own syntax and semantics. This language is used to reduce repetition in source code by providing functionality to inline files, define macros, and to conditionally omit code.

Before interpreting commands, the preprocessor does some initial processing. This includes joining continued lines (lines ending with a \) and stripping comments.

To print the result of the preprocessing stage, pass the -E option to cc:

cc -E hello_world.c
Given the “Hello, World!” example above, the preprocessor will produce the contents of the stdio.h header file joined with the contents of the hello_world.c file, stripped free from its leading comment:

[lines omitted for brevity]

extern int __vsnprintf_chk (char * restrict, size_t,
       int, size_t, const char * restrict, va_list);
# 493 "/usr/include/stdio.h" 2 3 4
# 2 "hello_world.c" 2

int
main(void) {
 puts("Hello, World!");
 return 0;
}

Compilation

The second stage of compilation is confusingly enough called compilation. In this stage, the preprocessed code is translated to assembly instructions specific to the target processor architecture. These form an intermediate human readable language.

The existence of this step allows for C code to contain inline assembly instructions and for different assemblers to be used.

Some compilers also supports the use of an integrated assembler, in which the compilation stage generates machine code directly, avoiding the overhead of generating the intermediate assembly instructions and invoking the assembler.

To save the result of the compilation stage, pass the -S option to cc:

cc -S hello_world.c
This will create a file named hello_world.s, containing the generated assembly instructions. On macOS 10.10.4, where cc is an alias for clang, the following output is generated:

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 10
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    leaq    L_.str(%rip), %rdi
    movl    $0, -4(%rbp)
    callq   _puts
    xorl    %ecx, %ecx
    movl    %eax, -8(%rbp)          ## 4-byte Spill
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz  "Hello, World!"


.subsections_via_symbols


Assembly

During this stage, an assembler is used to translate the assembly instructions to object code. The output consists of actual instructions to be run by the target processor.

To save the result of the assembly stage, pass the -c option to cc:

cc -c hello_world.c
Running the above command will create a file named hello_world.o, containing the object code of the program. The contents of this file is in a binary format and can be inspected using hexdump or od by running either one of the following commands:

hexdump hello_world.o
od -c hello_world.o

Linking

The object code generated in the assembly stage is composed of machine instructions that the processor understands but some pieces of the program are out of order or missing. To produce an executable program, the existing pieces have to be rearranged and the missing ones filled in. This process is called linking.

The linker will arrange the pieces of object code so that functions in some pieces can successfully call functions in other ones. It will also add pieces containing the instructions for library functions used by the program. In the case of the “Hello, World!” program, the linker will add the object code for the puts function.

The result of this stage is the final executable program. When run without options, cc will name this file a.out. To name the file something else, pass the -o option to cc:

cc -o hello_world hello_world.c