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

Sunday, May 26, 2013

snprintf()


Now I know that

       The  functions  snprintf()  and  vsnprintf()  do  not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to this limit then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if  enough space had been available. Thus, a return value of size or more means that the output was truncated.

Saturday, January 12, 2013

gcc: moving to compile time

NOTE: below is gcc specific.


It's always hard to come up with examples, let's say we have a processing item

struct __item {
        int flags;
        int prio;
        void *priv;
};

a number of possible types

#define IT_TYPE_A       (1 << 4)
#define IT_TYPE_B       (1 << 3)
#define IT_TYPE_C       (1 << 2)
#define IT_TYPE_ANY     (1 << 1)


and a usage example:

        struct __item it = {
                .flags = IT_TYPE_ANY | IT_TYPE_C,
                .prio = 0,
                .priv = "cron item processing",
        };
        [..]
        process_item(&it);



Let's say, we deprecate (you know, because of reasons(tm)) IT_TYPE_ANY field.
Now we need to check and correct passed items each time process_item() called,
even for compile-time known flag values, like the above one. In a trivial situation
this might be almost free operation, but it depends.

A solution could be to extract a happy path -- for compile time known
values, and a slow path -- for run-time checks and adjustments.

IOW, we need to hide our original process_item() and define new function

__fortify_function int process_item(struct __item *it)
{
        if (__builtin_constant_p (it->flags)) {
                if ((it->flags & IT_TYPE_ANY) != 0) {
                        __warn_type_any_deprecated();
                        it->flags &= ~IT_TYPE_ANY;
                        it->flags |= IT_TYPE_A;

                        /** something important **/
                }
        }
        return __process_item(it);
}


that'd be able to test and correct passed items. __builtin_constant_p() is a
gcc internal, that returns 1 if compiler can prove that value is correct and known
at compile time (with some exceptions), and __fortify_function is
__extern_always_inline __attribute_artificial__
.

We also might be interested in informing programmer about usage of a
deprecated flag value, therefore we define empty function

extern void __attribute__((deprecated)) __warn_type_any_deprecated() {};


Now compiler fires a warning each time it sees __warn_type_any_deprecated():

gcc -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -O2 test.c -o a.out
In file included from test.c:21:0:
item.h: In function ‘process_item’:
item.h:34:4: warning: ‘__warn_type_any_deprecated’ is deprecated (declared at item.h:25) [-Wdeprecated-declarations]


The good thing about this is that for __builtin_constant_p() case compiler will try
to do all checks and flag adjustments behind the scene, producing code directly
for "IT_TYPE_A | IT_TYPE_C" case:

    movl   $0x0,0x4(%rsp)
    movq   $0x4006be,0x8(%rsp)
    movl   $0x14,(%rsp)
    callq  0x400580 <__process_item>


note movl   $0x14,(%rsp) instead of movl   $0x6,(%rsp).

Developer, however, is still able to ignore (or simply miss) warning, so
for radical cases we can fail build process.

sys/cdefs.h header file contains several defines that could be useful

145 #if __GNUC_PREREQ (4,3)
146 # define __warndecl(name, msg) \
147   extern void name (void) __attribute__((__warning__ (msg)))
148 # define __warnattr(msg) __attribute__((__warning__ (msg)))
149 # define __errordecl(name, msg) \
150   extern void name (void) __attribute__((__error__ (msg)))
151 #else                                                                                
152 # define __warndecl(name, msg) extern void name (void)
153 # define __warnattr(msg)
154 # define __errordecl(name, msg) extern void name (void)
155 #endif



Changing __warn_type_any_deprecated() prototype to

__warndecl (__warn_type_any_deprecated, "\n\tWARNING: TYPE ANY has been deprecated");

will change output to:

gcc -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE -O2 test.c -o a.out
In file included from test.c:21:0:
In function ‘process_item’,
    inlined from ‘main’ at test.c:63:14:
item.h:34:30: warning: call to ‘__warn_type_any_deprecated’ declared with attribute warning:
    WARNING: TYPE ANY has been deprecated [enabled by default]


and fail linkage (pretty hard to ignore), because __warndecl() declares function
w/o body:

test.c:(.text.startup+0x1d): undefined reference to `__warn_type_any_deprecated'

Monday, May 28, 2012

GCC vector types


Apparently GCC has vector types for C language. Moreover, GCC 4.7 allows
to use vector generating element while performing operations with vector types.

Suppose we have

typedef int intvect __attribute__ ((vector_size (32)))

intvec a, b = {1,2,3,4,5,6,7,8};



Operation with vector generating element will be:

a = b + 2;

which literally means:

vector a{2,2,2,2,2,2,2,2} + vector b{1,2,3,4,5,6,7,8}


As it often happens, the neat stuff is hidden behind. Part of generated
assembler code:

    movl   $0x1,0x48(%rsp)
    movl   $0x2,0x4c(%rsp)
    movl   $0x3,0x50(%rsp)
    movl   $0x4,0x54(%rsp)
    movl   $0x5,0x58(%rsp)
    movl   $0x6,0x5c(%rsp)
    movl   $0x7,0x60(%rsp)
    movl   $0x8,0x64(%rsp)
    movdqa 0x48(%rsp),%xmm1
    movl   $0x2,-0x38(%rsp)
    movl   $0x2,-0x34(%rsp)
    movl   $0x2,-0x30(%rsp)
    movl   $0x2,-0x2c(%rsp)
    movl   $0x2,-0x28(%rsp)
    movl   $0x2,-0x24(%rsp)
    movl   $0x2,-0x20(%rsp)
    movl   $0x2,-0x1c(%rsp)
    movdqa -0x38(%rsp),%xmm0
    paddd  %xmm0,%xmm1
    movdqa 0x58(%rsp),%xmm2
    movl   $0x2,-0x58(%rsp)
    movl   $0x2,-0x54(%rsp)
    movl   $0x2,-0x50(%rsp)
    movl   $0x2,-0x4c(%rsp)
    movl   $0x2,-0x48(%rsp)
    movl   $0x2,-0x44(%rsp)
    movl   $0x2,-0x40(%rsp)
    movl   $0x2,-0x3c(%rsp)



I really like how they utilize CPU's out-of-order and data prefetching features
by filling pipeline with mov-s with high probability of simultaneous execution
instead of several loops.


"The core's ability to execute instructions out of order is a key factor in enabling
parallelism. This feature enables the processor to reorder instructions so that if
one µop is delayed while waiting for data or a contended resource, other µops that
appear later in the program order may proceed. This implies that when one portion
of the pipeline experiences a delay, the delay may be covered by other operations
executing in parallel or by the execution of µops queued up in a buffer."


Good example is glibc's strncmp:

 STRNCMP (const char *s1, const char *s2, size_t n)
 {
   unsigned char c1 = '\0';
   unsigned char c2 = '\0';

   if (n >= 4)
     {
       size_t n4 = n >> 2;
       do
         {
           c1 = (unsigned char) *s1++;
           c2 = (unsigned char) *s2++;
           if (c1 == '\0' || c1 != c2)
             return c1 - c2;
           c1 = (unsigned char) *s1++;
           c2 = (unsigned char) *s2++;
           if (c1 == '\0' || c1 != c2)
             return c1 - c2;
           c1 = (unsigned char) *s1++;
           c2 = (unsigned char) *s2++;
           if (c1 == '\0' || c1 != c2)
             return c1 - c2;
           c1 = (unsigned char) *s1++;
           c2 = (unsigned char) *s2++;
           if (c1 == '\0' || c1 != c2)
             return c1 - c2;
         } while (--n4 > 0);
       n &= 3;
     }

   while (n > 0)
     {
       c1 = (unsigned char) *s1++;
       c2 = (unsigned char) *s2++;
       if (c1 == '\0' || c1 != c2)
         return c1 - c2;
       n--;
     }
   return c1 - c2;
 }

Wednesday, December 21, 2011

C/C++ alternative preprocessing tokens

C++ has a set of alternative preprocessing tokens:
2.5/1
 and_eq &=
 and &&
 xor_eq ^=
 or ||

[..]


It turned out that C has them as well:
7.9
The header iso646.h defines the following eleven macros (on the left) that expand to
the corresponding tokens (on the right):

cat 4.6.3/include/iso646.h

#ifndef _ISO646_H
#define _ISO646_H

#ifndef __cplusplus
#define and     &&
#define and_eq  &=
#define bitand  &
#define bitor   |
#define compl   ~
#define not     !
#define not_eq  !=
#define or      ||
#define or_eq   |=
#define xor     ^
#define xor_eq  ^=
#endif

#endif


Wednesday, December 14, 2011

rq_of_rt_rq...


 kernel/sched_rt.c
 [..]
 113 static void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 114 {
 115         if (!rt_entity_is_task(rt_se))
 116                 return;
 117
 118         rt_rq = &rq_of_rt_rq(rt_rq)->rt;
 119
 120         rt_rq->rt_nr_total--;
 121         if (rt_se->nr_cpus_allowed > 1)
 122                 rt_rq->rt_nr_migratory--;
[..]

Try to read `rt_rq = &rq_of_rt_rq(rt_rq)->rt;' fluently :-)

Saturday, October 15, 2011

Bits of History

The C Family of Languages: Interview with Dennis Ritchie, Bjarne Stroustrup, and James Gosling

This article appeared in Java Report, 5(7), July 2000 and C++ Report, 12(7), July/August 2000.
VIa  gotw.ca

Thursday, October 13, 2011

Thank you Dennis

Dennis MacAlistair Ritchie
September 8, 1941 — October 8/9, 2011


" ... was an American computer scientist notable for developing C and 
for having influence on other programming languages, as well as operating
systems such as Multics and Unix... "





Image and text via wikipedia

Tuesday, June 7, 2011

GNU C Family Extensions

Some time ago I met confusing C ternary operator usage

return timeout ?: 1;


It turned out to be a GNU "Conditionals with Omitted Operands

C extension. The list of "Extensions to the C Language Family" can be found here.

This page is worth reading. For example, getting
the address of a label defined in the current function (or a containing
function) with the unary operator `&&'. The value has type void *. This value
is a constant and can be used wherever a constant of that type is valid.
For example:
     void *ptr;
     /* ... */
     ptr = &&foo;
To use these values, you need to be able to jump to one. This is done with
the computed goto statement, goto *exp;.
For example,
     goto *ptr; 
 

Tuesday, December 21, 2010

2010 LLVM Developers' Meeting

Videos from `2010 LLVM Developers' Meeting' now available here

Friday, August 27, 2010

ANSI C vs ISO C++

Q:
int x = 0;
int y = 0;
(1 ? x : y) = 4;



A:
This is not legal in ANSI C:
6.5.15/4
If an attempt is made to modify the result of a conditional operator
or to access it after the next sequence point, the behavior is undefined.


However, in C++ we have:
5.16/4
If the second and third operands are lvalues and have the same type,
the result is of that type and is an lvalue.
5.16/5
Otherwise, the result is an rvalue.


via linkedin.com, cpptrivia.blogspot.com