__builtin_constant_p
                             =-=-=-=-=-=-=-=-=-=-=-

main(){char *s="main(){char *s=%c%s%c;printf(s,34,s,34);}";printf(s,34,s,34);}

          Představte  si, že chcete implementovat optimální memset. To jde
      udělat například:

extern inline void * memset(void * s, char c,size_t count)
{
asm volatile(
       "cld
        rep
        stosb"
        : /* no output */
        :"a" (c),"D" (s),"c" (count)
        :"cx","di","memory","cc");
return s;
}

          časem ale zjistíte, že volání memset(x,0,4096), které je časté v
      jádře  -  nulujou se tím stránky - je neoptimální, protože nuluje to
      byte po bytu, přesto, že by to šlo hned po čtyřech. Mnohem rychlejší
      je:

extern inline void * memset(void * s, char c,size_t count)
{
asm volatile (
       "cld
        rep
        stosl"
        : /* no output */
        :"a" (c+(c<<8)+(c<<16)+(c<<24)),"D" (s),"c" (count/4)
        :"cx","di","memory","cc");
return s;
}

          To  sice  nefunguje  pro  počty  nedělitelné  čtyřma,  ale jinak
      pracuje  pěkně. Ale zase můžou existovat volání třeba memset(s,0,4),
      pro  které je použití tohoto kódu vrhání atomových náloží na vrabce.
      Kdybychom  mohli  předpoklát,  že  count  je konstanta, mohli bychom
      napsat následující podivnost:

extern inline void * memset(void * s, unsigned long pattern, size_t count)
{
        pattern=pattern+(pattern<<8)+(pattern<<16)+(pattern<<24);
        switch (count) {
                case 0:
                        return s;
                case 1:
                        *(unsigned char *)s = pattern;
                        return s;
                case 2:
                        *(unsigned short *)s = pattern;
                        return s;
                case 3:
                        *(unsigned short *)s = pattern;
                        *(2+(unsigned char *)s) = pattern;
                        return s;
                case 4:
                        *(unsigned long *)s = pattern;
                        return s;
        }
#define COMMON(x) \
asm ("cld; rep ; stosl" \
        x \
        : /* no outputs */ \
        : "a" (pattern),"c" (count/4),"D" ((long) s) \
        : "cx","di","memory","cc")

        switch (count % 4) {
                case 0: COMMON(""); return s;
                case 1: COMMON("\n\tstosb"); return s;
                case 2: COMMON("\n\tstosw"); return s;
                case 3: COMMON("\n\tstosw\n\tstosb"); return s;
        }
#undef COMMON
}

          Toto  funguje  tak,  že  optimizer,  který už bude vedět hodnotu
      count  a pattern sám předpočte šifty na začátku a vybere tu správnou
      větev  switche.  A  tak  tento memset bude fungovat velmi rychle pro
      všechny konstantní patterny a počty.

          Jediný  problém  je, že bychom potřebovali memset pro konstantní
      parametry  a  memset  pro nekonstantní a nutit programátora, aby sám
      dával  pozor  na  to, co je konstanta a co není (někdy to vůbec není
      jednoduché,  hlavně  když  parametr  je  sice  proměná, ale je možné
      předpočítat její hodnotu)

          K  tomu  slouží  právě  __builtin_constant_p.  Ta vrátí 1, pokud
      parametr  je konstanta a jinak 0. Múžeme tedy napsat všechny memsety
      a potom vybrat ten správný pomocí:

#define __constant_c_x_memset(s, c, count) \
(__builtin_constant_p(count) ? \
 __constant_c_and_count_memset((s),(c),(count)) : \
 __constant_c_memset((s),(c),(count)))

#define __memset(s, c, count) \
(__builtin_constant_p(count) ? \
 __constant_count_memset((s),(c),(count)) : \
 __memset_generic((s),(c),(count)))

#define memset(s, c, count) \
(__builtin_constant_p(c) ? \
 __constant_c_x_memset((s),c,(count)) : \
 __memset((s),(c),(count)))

          Zkušenému  céčkaři  už  možná vstávájí vlasy na hlavě a řve:a co
      memset(s,c++,count)?  kolikrát  se mi to c zvětší? Ale ani on nemusí
      mít  obavy  - parametry funkce __builtin_constant_p se nevyhodnocují
      takže i program:

main()
{
   int a = 1;
   __builtin_constant_p(a++);
   __builtin_constant_p(a++);
   printf("%i\n", a);
}

          vypíše  jedna.  Takže  tento  memset je plnohodnoutnou náhražkou
      builtinu  do  překladače a má tu výhodu, že každý jej může upravovat
      podle  svých  potřeb  -  na  velikost,  rychlost, přidat další spec.
      připady,  pro různé CPU apod. Kompletní implementaci memsetu najdete
      ve string.h, který se dá exportovat z hlavní stránky tohoto článku

          Je  nutné  poznamenat,  že __builtin_constant_p nepatří zrovna k
      nejspolehlivějším. Její hodnota se určuje před propagací konstant (v
      té  době  je  už  nutné  vědět,  kudy  se  program  vydá)  a tak i v
      předchozím  případě  bude  __builtin_constant_p  vracet  0,  protože
      parametrem  je  proměná (přesto, že při propagaci konstant se přijde
      na to, že její hodnota je 1). Z toho důvodu nemá smysl používat tuto
      funkci  na  parametry  inline  funkcí  a je nutné psát makra.A proto
      používejte jinou metodu, pokud to je možné.


            výheň