Search

Sponsored Links

Meta

Categories

Archives

Recent Posts

RSS Feeds

13
Apr

Why sizeof is an operator, not a function?

To calculate the size of an object, we need the type information.
This type information is available only at compile time.  At the
end of the compilation phase, the resulting object code doesn’t
have (or not required to have) the type information.

Of course, type information can be stored to access it at run-time,
but this results in bigger object code and less performance.  And
most of the time, we don’t need it.

All the runtime environments that support run time type
identification (RTTI) will retain type information even after
compilation phase.  And if, something can be done in compilation
time itself, why do it at run time?

More importantly, HOW can it be a function when the operand is a
type, not an expression. Even expressions subject to integral
promotion are problematic.

Popularity: 10%

13
Apr

What is allowed in C, but not in C++?

    Following are few differece in C and C++.  Few of these are allowed in
C++, but with a different meaning; while some are illegal.

1.  sizeof (’1′) == sizeof (int) in C; but it is sizeof (char) in C++.

2.  You generally should NOT use *alloc()/free() in C++; but they are the
    only such functions in C.  Use new and delete combination, instead.

3.  Functions need not be prototyped in C; but, it’s a must in C++.
    Peter Nilsson says:

       "C99 changed from C90 in that named functions must be _declared_ prior
        to usage, but there is still no requirement that the function be
        prototyped. [The exception being variadic functions like printf,
        which have always required prototypes in standard C.]"

4.  struct a {
        struct b {
            int a;
        };
    };

    struct b b;         /* allowed in C; but, not in C++ */

5.  const int b = 1;    /* allowed in C and C++ */
    const int a;        /* allowed in C, but not in C++ */

6.  Global variables can be defined more than once in C, not in C++.
    int a;              /* both in C and C++ */
    int a = 10;         /* legal in C; illegal in C++ */

7.  const a;            /* allowed in C; illegal in C++ */

    This is equivalent to const int a; in C.

8.  char s[7] = "vijoeyz";  /* error in C++, but allowed in C */

9.  K&R style function definitions are not allowed in C++.  Example:

    void mango ( a )
    int a;
    {   …  }

Popularity: 9%

30
Mar

Stream buffering

The following program doesn’t "seem" to print "hello-out".  What is
the reason behind it?

#include <stdio.h>
#include <unistd.h>
int main()
{
    while(1)
    {
        fprintf(stdout,"hello-out");
        fprintf(stderr,"hello-err");
        sleep(1);
    }
    return 0;
}

When you observe, it looks as if the program prints only "hello-err".
But then, all of sudden, it prints "hello-out" in a bulk!  Why the
program should behave like that when it should print "hello-out" and
"hello-err" in sequence?

If you understand the concept of buffering, you will come know to why
the above program behaves like this.

Streams are of two types:  buffered and unbuffered.  Streams also can
also be categorized as text streams and binary streams.  However, on a
system like UNIX, these are identical.  Text streams that are buffered
are flushed when any of the following conditions are met:

   - The buffer is full
   - When ‘\n’ is encounterd, if the stream is line buffered
   - When a function to read from stdin is invoked
   - When the program exits
   - If the default flushing behaviour is modified by the setvbuf(3)
     library function.

Whereas, unbufferd stream are flushed as soon as the data arrive.
stderr is unbuffered by default, because this stream is used for error
reporting, and error reporting should not be delayed by buffering.

Run the above program without change and see that after some time
"hello-out" is printed in bulk.  stdout is line buffered, so if you
replace the above

    fprintf(stdout,"hello-out");

with

    fprintf(stdout,"hello-out\n");

"hello-out" is printed in iteration.

To know more on streams, refer K&R-II, section B.1.

Popularity: 6%

15
Mar

ANSI C Vs K&R C

There are three important differences between ANSI C and K&R C:

  • The first feature is the prototype - writing the parameter types as a part of the function declaration.  Prototypes make it easy for a compiler to check function use with definition.
     
  • Second feature is the addition of new keywords -
    • enum for enumerated types
    • const
    • volatile
    • signed
    • void

And the ‘entry’ keyword was retired.

  • Third category is of "silent changes" - some features that still compiles, but now has a slightly different meaning.  For example, now that the preprocessing rules are more tightly defined, there’s a new rule that adjacent string literals are concatenated.

 

Popularity: 6%

15
Mar

A tip for writing conditional statements

Did you know that the following if statement is semantically right, but could logically be wrong?

    if ( i = 2 )
    {
        /* do something */
    }   

Tip:

The compiler may only produce a waring: "Possibly incorrect assignment", but we may ignore it.  To avoid such a mistake, just reverse the two identifiers.

    if ( 2 == i )
    {
        /* do something */
    }

If ‘==’ is replaced by an ‘=’, the compiler will give an error saying "Lvalue required".

Note:  This post is just to provide a hint and may not suit to your coding style.

Popularity: 5%

15
Mar

A note on using Unions

Consider the following program -

    #include <stdio.h>

    int
    main ( void )
    {
        union {
         int     _i;
         float   _f;
        }_u = { 10 };

        printf ( "%f\n", u.f );
        return 0;
    }

Keep the following points on how a union object is represented in the memory:

  • The size of an union object is equal to size of it’s largest member.
  • Address of every member of an union object is same.
  • A union can not have an instance of itself, but a pointer to instance of itself.

Let me introduce two terms: Object Representation and Object Interpretation

Simply speaking, object representation is the pattern of bits of an object in the storage unit.  And, object interpretation is the meaning of the representation.

In the above example, union members _i and _f reside in the same memory location, say M.  The union object _u has been initialized to 10 which by default is assigned to the first member of the union.  Since _i and _f has the same location, their object representation is also the same, but their interpretation would be different.  Let us assume that a C implementation (i.e., compiler) uses 2’s complement for integers and IEEE 754 floating point format for float.  Though, the bit pattern for _i and _f appear identical in the storage unit, their interpretation is different.  Hence, if you thought that the above printf would print 10.000000, then you are wrong.  The output of this program is unspecified.

Popularity: 5%

17
Feb

String Reversal

/*!
 * string_reverse.c: Reverse a string  Feb 17, 2006
 */
#include <stdio.h>
#include <string.h>

void reverse_str(char *str, int start, int end)
    {
    char c = str[start];
    str[start] = str[end];
    str[end] = c;

    start++;
    end–;
    if (start < end)
        reverse_str(str, start, end);
    }

int main ()
    {
    char str[] = "vijoeyz";
    int len = strlen(str);
    reverse_str(str, 0, len-1);
    puts(str);
    return 0;
    }

Popularity: 25%

16
Feb

IEEE 754 Binary Floating Point Representation

How the floating point values are stored?

Note:  Please note that this discussion is not related to the C Language.

To be able to represent floating point numbers in the bit pattern, one needs
to know about IEEE 754, the floating point specification.  So, read patiently.

IEEE Floating Point Format:
---------------------------

    3 3          2         1         0
    1 09876543 21098765432109876543210
    +-+--------+-----------------------+
    |s| be     |       fraction        |
    +-+--------+-----------------------+

    be - biased exponent.  It is a constant, 127, for 32-bit
         floating point number.  This is also know as
         Mantisa(M).

    The general form of a floating point number is:
    x = s * M * B^p

        where,  s is sign bit
                M is normalized mantissa (1.fffff for IEEE 754)
                B is base ( 2 for IEEE 754 )
                p is integer power (explained below)

                ^ stands for exponentiation

    (Note: The 1 of 1.fffff is not explicitly stored in the memory)

    The general form would be: x = s * 1.ffff .. fff (binary) * 2^p

    This would not solve the problem unless an example or two are given.

    Example 1:  Convert 5.75 to binary floating point.

    The integer part is 101.
    The fractional part is found by

        0.75 * 2    =   1.5     (1)
        0.5  * 2    =   1.0     (1)
        0.0  * 2    =   0.0     (0)   so it terminates

    So, the number is 101.110
    This is the mere binary floating point representation of 5.75
    To make it IEEE 754 compliant, we have to have the normalized
    mantissa.

    So,
        101.110 = 1.01110 * 2^2
        therefore, M = 1.01110  and
                   p = 2

        be = p + 127 = 2 + 127 = 129 i.e., 1000 0001 (binary)
        The fractional part is 0.01110...

    So, the IEEE 754 representation of 5.75 becomes:

        0 1000 0001 01110 0000 0000 0000 0000 000

    Example 2:  Convert -0.1 to binary floating point

    The fractional part is found by

        0.1  * 2    =   0.2     (0)
        0.2  * 2    =   0.4     (0)
        0.4  * 2    =   0.8     (0)
        0.8  * 2    =   1.6     (1)
        0.6  * 2    =   1.2     (1)
        0.2  * 2    =   0.4     (0)     which repeats 0.2 above
        0.4  * 2    =   0.8     (0)
        0.8  * 2    =   1.6     (1)

    So, the fractional part is 0.000110011...

    0.000110011  =  1.1001100 * 2^(-4)
    therefore,  M = 1.1001100
                p = -4

    be = 127 + p = 127 - 4 = 123 i.e., 0111 1011 (binary)
    The fractional part is 1001 1000 ....

    So, the IEEE 754 representation of 5.75 becomes:

        1 01111011 1001 1000 0000 0000 0000 000

Popularity: 28%

16
Feb

ASCII Case Conversion

/*
 * case_conv.c  -   Program to change case without using arithmetic
 *                  operators or library functions.  This program
 *                  works ONLY if the charcter set is ASCII, and hence
 *                  is not portable.  It is here, only as an example,
 *                  to convey a logic as how it can be done.
 */

/*
 * Refer the ASCII table while tracing the following program:
 *
 * Letter           Upper(binary)       Lower(binary)
 * ——           ————-       ————-
 *
 *  A               0100 0001           0110 0001
 *  B               0100 0010           0110 0010
 *  …             …                 …
 *  O               0100 1111           0110 1111
 *  P               0101 0000           0111 0000
 *  …             …                 …
 *  Z               0101 1010           0111 1010
 */

#include <stdio.h>
#include <stdlib.h>

int
to_lower ( int ch )
{
    unsigned char _ch = (unsigned char)ch >> 4;

    /* If CH is already in lower case, return it */
    if ( _ch == 0×6 || _ch == 0×7 )
        return ch;

    /* convert it to lower case */
    if ( _ch == 0×4 )
        return (int)( ( (unsigned char)ch & 0×0f ) | 0×60 );
    else
    if ( _ch == 0×5 )
        return (int)( ( (unsigned char)ch & 0×0f ) | 0×70 );
    else
        return ch;
}

int
to_upper ( int ch )
{
    unsigned char _ch = (unsigned char)ch >> 4;

    /* If CH is already in upper case, return it */
    if ( _ch == 0×4 || _ch == 0×5 )
        return ch;

    /* convert it to upper case */
    if ( _ch == 0×6 )
        return (int)( ( (unsigned char)ch & 0×0f ) | 0×40 );
    else
    if ( _ch == 0×7 )
        return (int)( ( (unsigned char)ch & 0×0f ) | 0×50 );
    else
        return ch;
}

int
main ( void )
{
    printf ( "%c\n", to_upper ( ‘+’ ) );
    printf ( "%c\n", to_upper ( ‘r’ ) );
    printf ( "%c\n", to_upper ( ‘l’ ) );
    printf ( "%c\n", to_upper ( ‘P’ ) );

    printf ( "%c\n", to_lower ( ‘$’ ) );
    printf ( "%c\n", to_lower ( ‘R’ ) );
    printf ( "%c\n", to_lower ( ‘O’ ) );
    printf ( "%c\n", to_lower ( ‘9′ ) );
    return EXIT_SUCCESS;
}

Popularity: 11%

14
Feb

Bus Error

Bus error occurs when hardware tells the OS about a problematic memory reference.  In practice, a bus error is almost always caused by a misaligned read or write.  It’s called a bus error, because the address bus is the component that chokes if a misaligned load or store is requested.

union {
    char a[10];
    int i;
}u;

A bus error can also be generated by referencing memory that does not physically exist.

Alignment means that data items can only be stored at an address that is multiple of their size.

A program to cause a bus error is:

int *p = (int*) &(u.a[1]);
*p = 17;        /* the misaligned addr is p causes a bus error */

Simply, a bus error means that the CPU disliked something about that memory reference, while segv means that the MMU disliked something about it.

Popularity: 10%

Next Page »