Créer un programme C qui prend le plus de temps à compiler dans gcc


27

Créez un programme C court qui prend un temps absurde à compiler avec gcc. Les entrées seront notées en chronométrant la compilation puis en soustrayant le temps de compilation du programme de référence.

Règles

  • Toute fonctionnalité du langage C ou extension gcc
  • gcc 4.2.1

1
Modification du marquage car [code-golf] signifie explicitement "code court-circuité par (nombre de touches)".
dmckee

6
La division par le nombre de caractères n'a pas beaucoup de sens, car toute approche raisonnable de ce défi aura bien sûr une complexité de compilation plus grande O ( n ), c'est-à-dire que le score de n'importe quelle solution peut être trivialement augmenté en le faisant simplement un peu plus longtemps, ce qui sera probablement toujours possible de manière évidente.
cessé de tourner dans

Réponses:


13
#define a "xxxxxxxxxxx"
#define b a a a a a a a
#define c b b b b b b b
#define d c c c c c c c
#define e d d d d d d d
#define f e e e e e e e
#define g f f f f f f f
#define h g g g g g g g
#define i h h h h h h h
#define j i i i i i i i
z=j;

Ne compile pas sur ma machine
FUZxxl

19
Au minimum, la dernière ligne doit être changée en quelque chose comme main(){char*z=j;}pour en faire un programme c valide.
dmckee

2
Mon VS2012 sort de l'espace de stockage. Je suppose que je /Zmle corrigerais
rev

13

Les deux la réponse de Charlie et moi plus tôt un travail sur le principe de laisser l'écriture pré-processeur a beaucoup de code, mais ils exercent la plupart du temps lui - même pré-processeur, le lexer (bonne idée que cette étape a toujours été lent) et l'analyseur. Le mien essaie également de travailler les étapes d'optimisation et de génération de code, mais il n'y a clairement pas grand-chose là-bas.

En pensant au fonctionnement d'un compilateur c typique, j'ai réalisé que nous ne donnions rien au code lié à la table des symboles. Cette entrée est une tentative pour y remédier. Il est censé rappeler l'orientation d'objet de base dans l'implémentation c, mais ne fait rien d'intéressant: utilise la technique d'expansion du pré-processeur pour déclarer et initialise trivialement (et incorrectement) un tas d'objets. Objet qui utilise des types compliqués, à de nombreux niveaux de portée, se surveillant mutuellement à divers suppressions. Cela devrait donner à la table des symboles un vrai travail.

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
// Exercise the symbol table mechanism of the compiler in an effort to
// take a unreasonable about of time compiling

#define PTR(T) T*
#define CONST(T) T const
#define FUNC(NAME,RTYPE,ARG) RTYPE NAME(ARG)
#define FPTR(NAME,RTYPE,ARG) FUNC((*NAME),RTYPE,ARG)

// Forward decalration of repeated OO method pointers
typedef void* (*cctor_ptr)(void*this, void*that, ...);
typedef void* (*dtor_ptr)(void*this);

// Assumes three var-args: sizeof(payload type), cctor, dtor
void* default_ctor(void*this, ...){
  // Pull in variadac bits
  va_list list;
  va_start(list,this);
  int size=va_arg(list,int);
  cctor_ptr cctor=va_arg(list,cctor_ptr);
  dtor_ptr dtor=va_arg(list,dtor_ptr);
  va_end(list);
  // process
  if (!this) this = malloc(size);
  if (this) {
    memset(this,size,0);
    /* various dodges to install the cctor and dtor in the write places */
  }
  return this;
}
// Copies the payload from that to this; 
void* default_cctor(void*restrict this, void* restrict that, ...){
  // Pull in variadac bits
  va_list list;
  va_start(list,that);
  int size=va_arg(list,int);
  cctor_ptr cctor=va_arg(list,cctor_ptr);
  dtor_ptr dtor=va_arg(list,dtor_ptr);
  va_end(list);
  // process
  if (!this) this = malloc(size);
  if (this) {
    memcpy(this,that,size);
    /* various dodges to install the cctor and dtor in the write places */
  }
  return this;
}
// Assumes that his was allocated with malloc, does not use varargs
void* default_dtor(void*this, ...){
  free(this); 
  return NULL;
};

#define DECLARE_STRUCT(N) struct S##N##_s
#define TYPEDEF_ACCESSOR(N,T) typedef FPTR(f##N##_ptr,CONST(PTR(T)),PTR(CONST(struct S##N##_s)))
#define TYPEDEF_STRUCT(N,T) typedef struct S##N##_s {PTR(T)p; cctor_ptr cctor; dtor_ptr dtor; f##N##_ptr f##N;} S##N
#define OO_STRUCT(N,T) DECLARE_STRUCT(N); TYPEDEF_ACCESSOR(N,T); TYPEDEF_STRUCT(N,T)

OO_STRUCT(1,char);
OO_STRUCT(2,int);
OO_STRUCT(3,double*);
OO_STRUCT(4,S3);
OO_STRUCT(5,S4);
OO_STRUCT(6,S5);
OO_STRUCT(7,S6);
OO_STRUCT(8,S7);

#define SUBSCOPE(A) { \
    S1*A##1=default_ctor(NULL,sizeof(char),default_cctor,default_dtor); \
    S2 A##2; default_ctor(&A##2,sizeof(int),default_cctor,default_dtor); \
    S2*A##3=default_ctor(NULL,sizeof(double*),default_cctor,default_dtor); \
    S8 A##5; default_ctor(&A##5,sizeof(S4),default_cctor,default_dtor); \
    S6 A##6; default_ctor(&A##6,sizeof(S5),default_cctor,default_dtor); \
    S8*A##8=default_ctor(NULL,sizeof(S7),default_cctor,default_dtor); \
  }
#define SUBSCOPE2(A,B)  { \
    S2*B##5=default_ctor(NULL,sizeof(S4),default_cctor,default_dtor); \
    S4 A##7; default_ctor(&A##7,sizeof(S6),default_cctor,default_dtor); \
    SUBSCOPE(A) SUBSCOPE(B);                 \
  }
#define SUBSCOPE6(A,B,C)  { \
    S2*A##3=default_ctor(NULL,sizeof(double*),default_cctor,default_dtor); \
    S2 B##2; default_ctor(&B##2,sizeof(int),default_cctor,default_dtor); \
    S4*C##4=NULL;                           \
    SUBSCOPE2(A,C) SUBSCOPE2(B,C) SUBSCOPE2(A,B); \
  }
#define SUBSCOPE24(A,B,C,D) { \
    S1*D##1=default_ctor(NULL,sizeof(char),default_cctor,default_dtor); \
    S2 C##2; default_ctor(&C##2,sizeof(int),default_cctor,default_dtor); \
    S2*B##3=default_ctor(NULL,sizeof(double*),default_cctor,default_dtor); \
    S4 A##4; default_ctor(&A##4,sizeof(S3),default_cctor,default_dtor); \
    SUBSCOPE6(A,B,C) SUBSCOPE6(A,B,D) SUBSCOPE6(A,C,D) SUBSCOPE6(B,C,D); \
  }
#define SUBSCOPE120(A,B,C,D,E) { \
    S5*A##5=default_ctor(NULL,sizeof(S4),default_cctor,default_dtor); \
    S6*A##6=default_ctor(NULL,sizeof(S5),default_cctor,default_dtor); \
    S8 A##8; default_ctor(&A##8,sizeof(S7),default_cctor,default_dtor); \
    SUBSCOPE24(A,B,C,D) SUBSCOPE24(A,B,C,E) SUBSCOPE24(A,B,D,E); \
    SUBSCOPE24(A,C,D,E) SUBSCOPE24(B,C,D,E); \
  }
#define SUBSCOPE720(A,B,C,D,E,F) { \
    S5 A##5; default_ctor(&A##5,sizeof(S4),default_cctor,default_dtor); \
    S6 A##6; default_ctor(&A##6,sizeof(S5),default_cctor,default_dtor); \
    S8*A##8=default_ctor(NULL,sizeof(S7),default_cctor,default_dtor); \
    SUBSCOPE120(A,B,C,D,E) SUBSCOPE120(A,B,C,D,F) SUBSCOPE120(A,B,C,E,F); \
    SUBSCOPE120(A,B,D,E,F) SUBSCOPE120(A,C,D,E,F) SUBSCOPE120(B,C,D,E,F); \
  }

int main(){
  S4 s4;
  SUBSCOPE720(A,B,C,D,E,F)
}

Le temps de compilation sur ma machine dépasse 4 secondes avec -O3et plus de 1 seconde sans optimisation.


Évidemment, la prochaine étape serait de terminer l'implémentation OO pour une classe BCD et de refaire les calculs pi en l'utilisant pour que les deux effets fonctionnent dur.


12

Voici un riff du thème exponentiel-préprocesseur-expansion qui fait quelque chose de peu intéressant: calcule deux approximations de pi par des méthodes de série et compare avec la valeur dans math.het l'incantation habituelle.

Non golfé.

#include <math.h>
#include <stdio.h>

// Some random bits we'll need
#define MINUSONODD(n) (n%2?-1:+1)
#define TWON(n) (2*(n))
#define NPLUSONE(n) ((n)+1)
#define TWONPLUSONE(n) NPLUSONE(TWON(n))
#define FACT(n) (tgamma(NPLUSONE(n)))

// The Euler series
//                           2^(2n) * (n!)^2      z^(2n+1)
// atan(z) = \sum_n=0^\infty --------------- * ---------------
//                               (2n+1)!       (1 + z^2)^(n+1)
#define TERMEULER(n,z) (pow(2,TWON(n))*                 \
            FACT(n)*FACT(n)*                \
            pow((z),TWONPLUSONE(n))/            \
            FACT(TWONPLUSONE(n)) /              \
            pow((1+z*z),NPLUSONE(n)) )

// The naive version
//                           (-1)^n * z^(2n+1)
// atan(z) = \sum_n=0^\infty -----------------
//                                2n + 1
#define TERMNAIVE(n,z) (MINUSONODD(n)*pow(z,TWONPLUSONE(n))/TWONPLUSONE(n))


// Define a set of bifruncations of the sum
#define N2TERMS(n,z,ALG)  (TERM##ALG(TWON(n),(z)) + TERM##ALG(TWONPLUSONE(n),(z)))
#define N4TERMS(n,z,ALG)  (N2TERMS(TWON(n),(z),ALG)+N2TERMS(TWONPLUSONE(n),(z),ALG))
#define N8TERMS(n,z,ALG)  (N4TERMS(TWON(n),(z),ALG)+N4TERMS(TWONPLUSONE(n),(z),ALG))
#define N16TERMS(n,z,ALG) (N8TERMS(TWON(n),(z),ALG)+N8TERMS(TWONPLUSONE(n),(z),ALG))
#define N32TERMS(n,z,ALG) (N16TERMS(TWON(n),(z),ALG)+N16TERMS(TWONPLUSONE(n),(z),ALG))

// Sum the fist 32*2+16 = 80 terms of a series...
#define PARTIALSUM(z,ALG) N32TERMS(0,(z),ALG)+N32TERMS(1,(z),ALG)+N16TERMS(4,(z),ALG)


int main(void){
  const double PI_TRAD = 4.0L * atan(1.0);
  const double PI_NAIVE = 4.0L * PARTIALSUM(0.999999L,NAIVE);
  const double PI_EULER = 4.0L * PARTIALSUM(0.999999L,EULER);
  printf("pi (math.h) = %10.8f\n",M_PI);
  printf("pi (trad.)  = %10.8f\n",PI_TRAD);
  printf("pi (NAIVE)  = %10.8f\n",PI_NAIVE);
  printf("pi (EULER)  = %10.8f\n",PI_EULER);
}

Suppose que vous utilisez gccet que vous glibcpouvez ou non travailler avec d'autres arrangements. Il faut environ 1,0 à 1,1 secondes de temps processeur (évalué avec time (1)) pour compiler avec -031 sur mon MacBook Intel Core 2 Duo 2,4 GHz. Une compilation par défaut prend environ 0,4 seconde de temps processeur.

Hélas, je ne peux pas gcc pour évaluer soit powou tgammaau moment du compilateur, ce qui pourrait vraiment aider.

Lorsque vous l'exécutez, la sortie est:

pi (math.h) = 3.14159265
pi (trad.)  = 3.14159265
pi (NAIVE)  = 3.11503599
pi (EULER)  = 3.14159065

ce qui montre à quel point la série naïve converge lentement.


1 Pour obtenir autant de repliement constant et d'élimination de la sous-expression que possible.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.