tech_log: August 2009

Wednesday, August 12, 2009

Pomodoro technique and timer (applet) in Debian

http://www.pomodorotechnique.com/

http://timerapplet.sourceforge.net/
http://packages.debian.org/fr/lenny/timer-applet
http://www.flickr.com/photos/7982697@N05/sets/72157600138316537/detail/

Zero length arrays in C

http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg21219.html
http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

5.14 Arrays of Length Zero

Zero-length arrays are allowed in GNU C. They are very useful as the last element of a structure which is really a header for a variable-length object:

     struct line {
       int length;
       char contents[0];
     };
    
     struct line *thisline = (struct line *)
       malloc (sizeof (struct line) + this_length);

     thisline->length = this_length;


In ISO C90, you would have to give contents a length of 1, which means either you waste space or complicate the argument to malloc.

In ISO C99, you would use a flexible array member, which is slightly different in syntax and semantics:

    * Flexible array members are written as contents[] without the 0.
    * Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation of zero-length arrays, sizeof evaluates to zero.
    * Flexible array members may only appear as the last member of a struct that is otherwise non-empty.
    * A structure containing a flexible array member, or a union containing such a structure (possibly recursively), may not be a member of a structure or an element of an array. (However, these uses are permitted by GCC as extensions.)

GCC versions before 3.0 allowed zero-length arrays to be statically initialized, as if they were flexible arrays. In addition to those cases that were useful, it also allowed initializations in situations that would corrupt later data. Non-empty initialization of zero-length arrays is now treated like any case where there are more initializer elements than the array holds, in that a suitable warning about "excess elements in array" is given, and the excess elements (all of them, in this case) are ignored.

Instead GCC allows static initialization of flexible array members. This is equivalent to defining a new structure containing the original structure followed by an array of sufficient size to contain the data. I.e. in the following, f1 is constructed as if it were declared like f2.

     struct f1 {
       int x; int y[];
     } f1 = { 1, { 2, 3, 4 } };
    
     struct f2 {
       struct f1 f1; int data[3];
     } f2 = { { 1 }, { 2, 3, 4 } };


The convenience of this extension is that f1 has the desired type, eliminating the need to consistently refer to f2.f1.

This has symmetry with normal static arrays, in that an array of unknown size is also written with [].

Of course, this extension only makes sense if the extra data comes at the end of a top-level object, as otherwise we would be overwriting data at subsequent offsets. To avoid undue complication and confusion with initialization of deeply nested arrays, we simply disallow any non-empty initialization except when the structure is the top-level object. For example:

     struct foo { int x; int y[]; };
     struct bar { struct foo z; };
    
     struct foo a = { 1, { 2, 3, 4 } };        // Valid.
     struct bar b = { { 1, { 2, 3, 4 } } };    // Invalid.

     struct bar c = { { 1, { } } };            // Valid.
     struct foo d[1] = { { 1 { 2, 3, 4 } } };  // Invalid.



-------------------


The idea is to use this zero-length array as a reference to variable

length data that’d be stored using the struct. If you are wondering why
a pointer is not used, the size of a pointer would be non-zero, whereas
the size of a zero-length array is guaranteed to be zero.


-------------------


****************    Cool explanation   *********************************

On Tue, Mar 20, 2001 at 01:03:21PM -0600, Peter Seebach wrote:
> In message <[EMAIL PROTECTED]>, Shankar Agarwal writes:

> >Can someone pls tell me if it is possible to define an array of size 0.
>
> Not in C.

Actually you can (see below).  It depends on the compiler and how strict
you have it checking things.  It only works in this case because the

memory manager is allocating an entire page for the structure, not
just the size of the structure.

It's not uncommon to use this for message-based communications where you
have a header and payload  and want to use sizeof(struct message) to get

the header size, but also want to use foo.payload to access the message
itself.  In that case, it's more likely to be used as a cast on a buffer,
(e.g., ((struct message*) buffer)->payload)

Realize, tho, there's a potential portability issue, if you use this.


What follows was done on a NetBSD 1.5 system.

[24]% cat zero.c && make zero && ./zero
#include <stdio.h>

struct zero_array {
        int header;
        int payload[0];

};

int main()
{
        struct zero_array foo;

        foo.header=1;
        foo.payload[0]=10;
        foo.payload[1]=12;
        printf("Foo:\n\theader: %d\n", foo.header);
        printf("\tpayload 0: %d\n", foo.payload[0]);

        printf("\tpayload 1: %d\n", foo.payload[1]);
        return 0;
}
cc -O2   -o zero zero.c
Foo:
        header: 1
        payload 0: 10
        payload 1: 12




****************************************************************************


In message <[EMAIL PROTECTED]>, John Franklin writes:
>On Tue, Mar 20, 2001 at 01:03:21PM -0600, Peter Seebach wrote:

>> In message <[EMAIL PROTECTED]>, Shankar Agarwal writes:
>> >Can someone pls tell me if it is possible to define an array of size 0.

 
>> Not in C.

>Actually you can (see below).  It depends on the compiler and how strict
>you have it checking things.

The C language doesn't allow zero-sized objects.  Some systems may, but

C itself doesn't.

>What follows was done on a NetBSD 1.5 system.

More importantly, it was done with gcc, which (by default) compiles a
language called "GNU C", which is very similar to C, but has some extensions.


In C99, you can do this "portably" (C99 isn't exactly universally adopted yet)
by saying
        struct message {
                int header;
                char payload[];
        };


and then doing
        struct message *p;
        p = malloc(sizeof(struct message) + 10);
        p->header = 10;
        strcpy(p->payload, "123456789");


>int main()
>{

>        struct zero_array foo;
>
>        foo.header=1;
>        foo.payload[0]=10;
>        foo.payload[1]=12;


This isn't even a result of the page management, you're just overwriting

other space.

If you did
        struct zero_array foo;
        int a[2];

you would probably find that a[0] was 10, and a[1] was 12.  Probably.
The behavior is totally undefined, and it's not exactly reliable.  :)




-------


On Fri, Mar 30, 2001 at 10:37:28AM -0500, Lord Isildur wrote:
> sine one knows the size of the struct, who need the pointer? just
> take the displacement.
>

> char* buf; /* some buffer */
> struct foo{
> int header;
> struct funkystruct blah;
> };
>
> (struct foo*)buf; /*your headers are here */
> (struct foo*)buf+1; /* and your data is here */


Could, true. Buf if foo is:

struct foo{
 struct header head;
 struct funcystruct data[0];
}

you can say:
        mesg->head->headerbits;
        mesg->data[x]->databits;


A bit more readable, IMHO.

Tuesday, August 11, 2009

Debug TRACE() with variadic arguments

Define :

#ifdef DEBUG
#define TRACE(...) printf("DBG MESSAGE: " __VA_ARGS__)
#else
#define TRACE(...)
#endif


and then in program, you can use something like :

TRACE("my_array[%d]=%x\n", i , arr_val);


All the argument from TRACE() will be taken and substitued in the place of __VA_ARGS__, which will make printf to work well and print this message, with sentence DBG MESSAGE: in the begining.

Friday, August 7, 2009

strtoul() result begins with ffffffff

How is it possible that:
char bin[64];
char test[10] = "74";

bin[0] = strtoul (test, &e, 16);
printf("bin[0]=%#x\n", bin[0]);

is giving:
bin[0]=0x74

and if we put:
char test[10] = "84";

result printed is:
bin[0]=0xffffff84

Well, for all X in char test[10] = "X4"; that are less than 8, digit X starts with binary "0". For 8 and more, it will start with binary "1". Since we put "=" between char bin[64], thus SIGNED, and result that strtoul()  signed. Two things happen here:

1) Assignment conversion
An assignment conversion makes the value of the right operand have the same data type as the left operand.
(In assignment operations, the type of the value being assigned is converted to the type of the variable that receives the assignment. C allows conversions by assignment between integral and floating types, even if information is lost in the conversion.)
That means that our unsigned long return value of strtoul() becomes signed char.

2) Conversions from Unsigned Integral Types
An unsigned integer is converted to a shorter unsigned or signed integer by truncating the high-order bits, or to a longer unsigned or signed integer by zero-extending.
When the value with integral type is demoted to a signed integer with smaller size, or an unsigned integer is converted to its corresponding signed integer, the value is unchanged if it can be represented in the new type. However, the value it represents changes if the sign bit is set, as in the following example.

int j;
unsigned short k = 65533;

j = k;
printf_s( "%hd\n", j );   // Prints -3


Let's look at char. The highest positive value you can represent with one char is +127, i.e. 0x7F. Anything above this is represented as a negative. For example, 0x80 is actually -128, the biggest (in amplitude) negative number you can represent with char (and 0xFF is -1).

So, printing our result like this:
char test[10] = "80";
bin[0] = strtoul (test, &e, 16);
printf("bin[0]=%d\n", bin[0]);
drasko@Lenin:~/stuff$ ./test
bin[0]=-128

Makes more sense, because %#x switch was additional confusion, because it printed additional (starting) 3 bytes for negaitve number, putting them all into F.

RESOLUTION OF THE PROBLEM:
The buffer that takes result of assignment must be decleared as unsigned char, and not as signed char!

If we change
char bin[64];
to
unsigned char bin[64];
results will be good.




Wednesday, August 5, 2009

warning: implicit declaration of function ‘close’

#include <unistd.h>             /* definition of close() */

http://linux.die.net/man/2/close

warning: implicit declaration of function ‘htons’

Include <netinet/in.h> instead of <linux/in.h> to get htons()
prototpye.


ether_ntoa() format

ether_ntoa_r.c - glibc-2.3.5/inet :
char *
ether_ntoa_r (const struct ether_addr *addr, char *buf)
{
  sprintf (buf, "%x:%x:%x:%x:%x:%x",
           addr->ether_addr_octet[0], addr->ether_addr_octet[1],
           addr->ether_addr_octet[2], addr->ether_addr_octet[3],
           addr->ether_addr_octet[4], addr->ether_addr_octet[5]);
  return buf;
}


That means that if we have some of the bytes like 5, or 0, we can get an address like this :
5:3a:31:0:34:1c

This is not adequate if we want to be sure that value has been printed always with two nubers between ':'.

That's why we can a coriged solution :
sprintf (mac, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
           ea.ether_addr_octet[0], ea.ether_addr_octet[1],
           ea.ether_addr_octet[2], ea.ether_addr_octet[3],
           ea.ether_addr_octet[4], ea.ether_addr_octet[5]);



Monday, August 3, 2009

error: expected ')' before '*' token

This kind of error is reported by compiler when it tries to parse sybols it does understand, because they were not reported to it - proper my_type_def.h header file is missing.

my_error_t my_function(my_type_t *my_pointer)
{
   ...
}

Here, because #include my_header.h (where my_type_t is defined) is missing, compiler is telling us this message.

Solution :
include proper headers!