Showing posts with label c. Show all posts
Showing posts with label c. Show all posts

2010-08-15

Happy debugging

#define TRUE FALSE /* Happy debugging, suckers! */

2010-05-21

Undefined increment

#include <stdio.h>

#define COMPUTE(x,y) ((x*x*x) + (y))

int main()
{
        int num1 = 100;
        int num2 = 10;

        printf("%d\n", COMPUTE(++num1, num2));

        return 0;
}
The result is undefined in both C and C++, but the behavior is consistent and interesting. The result is in the first comment.
compute.c:10: warning: operation on ‘num1’ may be undefined
Attention by http://synsecblog.com/

2010-05-12

Programming homework

https://groups.google.com/group/comp.lang.c/msg/e105e5d339edec01?pli=1

> Dear everyone,

> Can someone please help me on my HW. I'm trying to write a program
> that will display the following:

>     *
>    ***
>   *****
>  *******
> *********
> *********
>  *******
>   *****
>    ***
>     *

> I'm having a hard time writing a code for this one. I tried several
> times, but I can't get it to work properly. I live in Japan and I take
> an online C++ course. The instructor lives in the US so whenever I am
> awake, he's asleep. Therefore, I cannot contact him directly when I
> need help. I have to get this program up and running ASAP. I tried
> searching everywhere for help, but there's none except for this group.
> My textbook isn't much of a help either. I WILL GREATLY APPRECIATE THE
> HELP I WILL GET!

My pleasure.

#define      M 002354l
#define     A   000644l
#define    G     000132l
#define     I   000322l
#define      C 000374l

#define                a ;
#define               b for
#define              c    ++
#define             d       %
#define            e       int
#define           f           ,
#define          g             -
#define         h             011
#define        i                 =
#define       j                   {
#define      k                     )
#define     l                    '\n'
#define    m                      main
#define    n                         <
#define     o                       }
#define      p                     >
#define       q                  &&
#define        r                 (
#define         s              ||
#define          t             ?
#define           u     putchar
#define            v      void
#define             w     '*'
#define              x     :
#define               y ' '
#define                _ /
#define           C_O_O_L return

                   e u r e k a

                         e
                        m r
                       v k j
                      j j j j
                     j j j j j
                    j j j j j j
                   j j j j j j j
                  j e z a b r z i
                 M _ A _ G _ I _ C
                a z n G a u r z d h
               + z _ h p M _ A q z d
              h + z _ h n M _ G q z _
             h n z d h + M _ I q z _ h
            p z d h g M _ C t w x y k f
           z d h g h + 1 s u r l k f z c
          k a u r l k a j j j j j j j j j
         j j C_O_O_L M _ A _ G _ I _ C a o
        o o o o o o o o o o o o o o o o o o
                      o o o o
                      o o o o
                      o o o o
                      o o o o 
-- 
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: masked

2010-05-03

C/C++: undefined behavior explained

Figure #1:
char *s = "Hello?";
s[5] = '!';
printf("%s\n",s);
Figure #2:
char *s = "Hello?";
char s2[] = "Jumbo?";
s = s2;
s[5] = '!';
printf("%s\n",s);

It is impossible to tell that the line s[5] = '!'; contains error or not. You can have some speculation according to some static code analysis, but you cannot tell for sure. That's why it will be a run-time error (if it is an error).

Writing a string literal leads to undefined behavior. If we would say that in this case the compiler must generate a code that crashes, then it would be a feature, some kind of requirement for the compiler's manufacturer. Every usage of char * for writing would have a literal-check, which obviously has a very large overhead. The writers of the standard decided not to make any behavioral requirements in such cases. After that you can imagine other undefined behavior cases or you can look them up and think about each of them individually.

Back to the example! In some cases it will lead to changing the literal, in other cases it will crash with "access violation" or "segmentation fault", because we are trying to write to a read-only area of the memory. ... To avoid accidents, I (the const fetishist) recommend you this:

const char *s = "Hello?";

You will have a compile time error instead of undefined behavior and you can fix your code and-or idea.

2010-04-26

Yes, it is C. The "const" keyword

The const qualifier can have multiple useful meanings depending on the context.
  • In parameter list
    size_t strlen(const char *s);
    The programmer of strlen() promises you that he/she will not alter the content pointed by s. It is good for you: You do not have to look up the manual for that bit of information. It tells more than you may think for the first time. It is good for the implementor of strlen(). He cannot accidentally write to the area pointed by s.

  • Storing partial results as read-only variables.
    const double aplusb = a + b;
    const double amulb = a * b;
    return 2*amulb/aplusb; // harmonic mean
    
    It helps avoiding accidents and ease interpretation by humans.

  • Pointing to literals
    const char *appname = "Hello World!";
    
    If you turn on the displaying of warnings in your compiler then you will see that pointing to a literal with non-const pointer is discouraged. It also helps not making bugs.
Note: It was borrowed from C++. In C++ you have to use initializer list in the constructor when you have const (or reference type) data members... A little bit different topic.

Exit strategy: Single exit point is less readable

Single exit point produces the pyramid of code syndrome.

bool solve2
    (
        double a, double b, double c
        , double& x1, double& x2
    )
{
    bool ret = true;
    if(a!=0) {
        double det = b*b - 4*a*c;
        if(det>=0) {
            ret = true;
            det = sqrt(det);
            double p2a = 1 / (2*a);
            x1 = (-b - det) * p2a;
            x2 = (-b + det) * p2a;
            // The top of the code pyramid
        } else
            ret = false;
    } else
        ret = false;
    return ret;
}

Using early returns helps keeping the error handing and productive code apart.

bool solve2
    (
        double a, double b, double c
        , double& x1, double& x2
    )
{
    // Checking for trivial errors and trivial solutions
    if(a==0)
        return false;
    double det = b*b - 4*a*c;
    if(det<0)
        return false;
    // Main part without pyramid
    det = sqrt(det);
    double p2a = 1 / (2*a);
    x1 = (-b - det) * p2a;
    x2 = (-b + det) * p2a;
    return true;
}

Note: This function solves the quadratic equation (a * x^2 + b * x + c = 0).

Note: You have to be careful with the multiple exit point style if you are acquiring resources (opening files, allocating memory, ...), because it can lead to leaks. Avoiding these kind of leaks is simpler in C++ than in most languages, because the lifetime of acquisitions can be bound to scope.

Yes, it is C. Smaller scope better scope

Once upon a time there lived a paradigm (sorry, that is an ugly word, but I don't know better) which told the programmer to declare all the variables at the beginning of the function. This paradigm was enforced by the compiler in Pascal, C and many other languages. You can guess. It was easier to write compilers that way. Then came the new winds with C++ (maybe it wasn't the first) which introduced RAII (Resource acquisition is initialization) which gave us three brand new concepts at once.
  • Variable scoping
  • Lifecycle management by scope (calling destructor when execution reaches the end of it's scope)
  • Bounding lifecycle of a variable to an object
Many may not know but since C99 the first is also available in C. A trivial example of it is the in-place declaration of iterator in for.
for(int i=0; i<10; ++i){ printf("%d^2 = %d\n",i,i*i); }
The new paradigm (woof) is that a variable should have the smallest scope possible to ease reading and interpretation of code (by humans).

Next: Exit strategy: Single exit point can be easily bad.