27
11
Create a short C program that takes an absurdly long time to compile with gcc. Entries will be scored by timing the compilation then subtracting the reference program's compile time.
Rules
- Any C language feature or gcc extension
- gcc 4.2.1
27
11
Create a short C program that takes an absurdly long time to compile with gcc. Entries will be scored by timing the compilation then subtracting the reference program's compile time.
Rules
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;
Does not compile on my machine – FUZxxl – 2012-11-04T22:04:03.920
19At a minimum the last line needs to be changed to something like main(){char*z=j;}
to make this a valid c program. – dmckee --- ex-moderator kitten – 2012-11-05T20:53:04.460
2My VS2012 gets out of heap space. I guess /Zm
would fix it – rev – 2014-07-29T21:27:59.467
13
Both Charlie's answer and my earlier one work on the principle of letting the pre-processor write a lot of code, but they mostly exercise the pre-processor itself, the lexer (good idea as this step has traditionally been slow) and the parser. Mine also attempts to work the optimization and code generation steps, but it is clearly not gaining a lot there.
Thinking about how a typical c compiler works, I realized that we weren't giving the symbol table related code anything to do. This entry is an attempt to remedy that. It is supposed to be reminiscent of basic object-orientation in c implementation, but doesn't do anything interesting: justuses the pre-processor expansion technique to declare and trivially (and incorrectly) initializes a bunch of objects. Object that use complicated types, on many levels of scope, shadowing each other at various removes. It ought to give the symbol table a real work out.
#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)
}
Compile time on my machine is in excess of 4 seconds with -O3
and more than 1 second with no optimization.
Obviously the next step would be to finish the OO implementation for a BCD classes and re-do the pi calculations using it so that I get both effects running hard.
12
Here's a riff of the exponential-preprocessor-expansion theme which does something minimally interesting: computes two approximations to pi by series methods and compares with both the value in math.h
and the usual incantation.
Ungolfed.
#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);
}
Assumes that you are using gcc
and glibc
and may or may not work with other arrangements. It takes about 1.0-1.1 seconds of processor time (evaluated with time (1)
) to compile on with -03
1 on my 2.4 GHz Intel Core 2 Duo MacBook. A default compile takes about 0.4 seconds of processor time.
Alas, I can't get gcc to evaluate either pow
or tgamma
at compiler time, which would really help.
When you run it the output is:
pi (math.h) = 3.14159265
pi (trad.) = 3.14159265
pi (NAIVE) = 3.11503599
pi (EULER) = 3.14159065
which shows just how slowly the naive series converges.
1 To get as much constant folding and sub-expression elimination as possible.
1Changed the tagging because [code-golf] explicitly means "shorted code by (key) stroke count". – dmckee --- ex-moderator kitten – 2012-11-02T02:37:33.570
6Dividing by the number of characters doesn't make much sense, because any reasonable approach to this challenge will of course have a compile-time–complexity larger O ( n ), i.e. the score of any solution can be trivially increased by just making it a bit longer, which will probably always be possible in an obvious way. – ceased to turn counterclockwis – 2012-11-02T19:55:21.930