This is What Peak Hello World Looks Like

栏目: IT技术 · 发布时间: 4年前

内容简介:Everybody’s done a Hello World program before. But now that I’ve got a few years of experience with the language, I set out to ask one of the most pressing questions out there - how do we make Hello World in C as convoluted and hard to understand as possib

Everybody’s done a Hello World program before. But now that I’ve got a few years of experience with the language, I set out to ask one of the most pressing questions out there - how do we make Hello World in C as convoluted and hard to understand as possible? This post documents the final result of a sleep-deprived me trying to do exactly that.

I quickly realized I had to set a few ground rules first so there would be a sensible limit for lines of code that are “useless”:

  • Since we’re using pure C, we won’t have classes (so no HelloWorldFactoryFactoryFactorySingleton s)
  • All #include directives should be essential to the program (so no chaining a billion .h files)
  • Each function must do something essential to the program (so no functions that just call another or useless #defines )
  • The program takes no input, and writes Hello World! exactly to the terminal (so no other calculations are done)

With that, let’s start by building our string in a separate function with malloc instead:

#include <stdio.h>
#include <stdlib.h>

char* generate_words() {
  char* ret = malloc(13);

  ret[0] = 'H';
  ret[1] = 'e';
  ret[2] = 'l';
  ret[3] = 'l';
  ret[4] = 'o';
  ret[5] = ' ';
  ret[6] = 'W';
  ret[7] = 'o';
  ret[8] = 'r';
  ret[9] = 'l';
  ret[10] = 'd';
  ret[11] = '!';
  ret[12] = '\0'; // Can't forget our null operator!

  return ret;
}

int main() {
  char *ret = generate_words();
  printf(ret);
  free(ret);
  return 0;
}

That’s already much more complicated than before, but we can make it even worse! Replacing our direct assignments of letters to bitwise operations gets us this monstrosity:

#include <stdio.h>
#include <stdlib.h>

char* generate_words() {
  char* ret = malloc(12);
  char c = 0x01;

  ret[0] = (c << 6) | (c << 3); // H is 0x48
  ret[1] = c | (c << 2) | (c << 5) | (c << 6); // 'e' is 101
  ret[2] = ((c | (c << 1)) << 2) | ((c | (c << 1)) << 5); // 'l' is 108
  ret[3] = ((c | (c << 1)) << 2) | ((c | (c << 1)) << 5); // 'l' is 108
  ret[4] = (c | (c << 1)) | ((c | (c << 1)) << 2) | ((c | (c << 1)) << 5); // 'o' is 111
  ret[5] = (c << 5); // ' ' is 32
  ret[6] = c | (c << 2) | (c << 1) | (c << 1) << 3 | (c << 1) << 5; // 'W' is 87
  ret[7] = (c | (c << 1)) | ((c | (c << 1)) << 2) | ((c | (c << 1)) << 5); // 'o' is 111
  ret[8] = (c << 1) | ((c << 1) | (c << 2) | c) << 4; // 'r' is 114
  ret[9] = ((c | (c << 1)) << 2) | ((c | (c << 1)) << 5); // 'l' is 108
  ret[10] = (c << 2) | (c << 5) | (c << 6); // 'd' is 100
  ret[11] = (c << 5) | c; // '!' is 33

  return ret;
}

int main() {
  char *ret = generate_words();
  printf(ret);
  free(ret);
  return 0;
}

As you can see, I’ve added comments and some extra brackets for readability’s sake. However, what if we remove our c variable to save space and only depend on previously defined values in ret for our calculations?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

volatile u_int8_t a = 0 - 1;
volatile u_int8_t * z = NULL;

int main() {
    a == 0 - 1 ? z = aligned_alloc(sysconf(_SC_LEVEL1_DCACHE_LINESIZE), 1 * 10 + 3) : a != 1 * 10 + 3 ? z[a] = a == 0 ? z[a] = (1 << (a + 6)) | (1 << (a + 3)) : a == 1 ? (z[a - 1] & (1 << (a + 5))) | (z[a - 1] >> a) | (z[a - 1] >> (a + 5))  : a == 2 ? z[a - 2] | z[1] & ~(z[a - 2] >> (a + 4)) : a == 4 ? z[a - 2] | z[a - 3] | (z[a - 4] >> (a + 1)) : a == 5 ? (z[a - 4] & z[a - 3] & z[a - 5]) >> (a - 4) : a == 6 ? (z[a - 2] & ~z[a - 1] | (z[a - 6] >> (a - 4))) & ~(z[a - 6] >> (a - 2) << (a - 5)) : a == 8 ? (~z[a - 7] & z[a - 2]) | z[a - 3] | z[a - 3] << (a - 7) : a == 10 ? z[a - 9] & ~(z[a - 5] >> (a - 5)) : a == 11 ? z[a - 6] | ((z[a - 1] & z[a - 3]) >> (a - 5)) : a - a : 0; if(a == 1 * 10 + 3) {memcpy(z + 3, z + 2, 1);memcpy(z + 9, z + 3, 1);memcpy(z + 7, z + 4, 1);printf("%s", z);free(z);return 0;}a = a + 1;main();
}
u_int8_t* generate_words() {
  u_int8_t * ret = malloc(13);

  ret[0] = (1 << 6) | (1 << 3);
  ret[1] = (ret[0] & (1 << 6)) | (ret[0] >> 1) | (ret[0] >> 6);
  ret[2] = ret[0] | ret[1] & ~(ret[0] >> 6);
  ret[4] = ret[2] | ret[1] | (ret[0] >> 5);
  ret[5] = (ret[1] & ret[2] & ret[0]) >> 1;
  ret[6] = (ret[4] & ~ret[5] | (ret[0] >> 2)) & ~(ret[0] >> 4 << 1);
  ret[8] = (~ret[1] & ret[6]) | ret[5] | ret[5] << 1;
  ret[10] = ret[1] & ~(ret[5] >> 5);
  ret[11] = ret[5] | ((ret[10] & ret[8]) >> 6);
  ret[12] = 0;

  memcpy(ret + 3, ret + 2, 1);
  memcpy(ret + 9, ret + 3, 1);
  memcpy(ret + 7, ret + 4, 1);

  ret[12] = 0;

  return ret;
}

int main() {
  u_int8_t *ret = generate_words();
  printf("%s", ret);
  free(ret);
  return 0;
}

Now our code’s starting to look good (bad?). The only problem is that it takes way too long to run - my super-powerful laptop processor from two years ago took nearly 5 milliseconds to run it! Well, we could also optimize it to be cache-aligned for maximum performance :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zconf.h>

u_int8_t* generate_words() {
    u_int8_t * ret = aligned_alloc(sysconf(_SC_LEVEL1_DCACHE_LINESIZE), 13);

    ret[0] = (1 << 6) | (1 << 3);
    ret[1] = (ret[0] & (1 << 6)) | (ret[0] >> 1) | (ret[0] >> 6);
    ret[2] = ret[0] | ret[1] & ~(ret[0] >> 6);
    ret[4] = ret[2] | ret[1] | (ret[0] >> 5);
    ret[5] = (ret[1] & ret[2] & ret[0]) >> 1;
    ret[6] = (ret[4] & ~ret[5] | (ret[0] >> 2)) & ~(ret[0] >> 4 << 1);
    ret[8] = (~ret[1] & ret[6]) | ret[5] | ret[5] << 1;
    ret[10] = ret[1] & ~(ret[5] >> 5);
    ret[11] = ret[5] | ((ret[10] & ret[8]) >> 6);
    ret[12] = 0;

    memcpy(ret + 3, ret + 2, 1);
    memcpy(ret + 9, ret + 3, 1);
    memcpy(ret + 7, ret + 4, 1);

    ret[12] = 0;

    return ret;
}

int main() {
    u_int8_t *ret = generate_words();
    printf("%s", ret);
    free(ret);
    return 0;
}

Well, now we’ve got way too many lines. Let’s trim down on it by getting rid of the function and putting our code into a for loop:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main() {
    u_int8_t * ret = aligned_alloc(sysconf(_SC_LEVEL1_DCACHE_LINESIZE), 13);

    for (__auto_type i = 0; i < 13; i++) {
        if (i == 0)
            ret[i] = (1 << (i + 6)) | (1 << (i + 3));
        else if (i == 1)
            ret[i] = (ret[i - 1] & (1 << (i + 5))) | (ret[i - 1] >> i) | (ret[i - 1] >> (i + 5));
        else if (i == 2)
            ret[i] = ret[i - 2] | ret[1] & ~(ret[i - 2] >> (i + 4));
        else if (i == 4)
            ret[i] = ret[i - 2] | ret[i - 3] | (ret[i - 4] >> (i + 1));
        else if (i == 5)
            ret[i] = (ret[i - 4] & ret[i - 3] & ret[i - 5]) >> (i - 4);
        else if (i == 6)
            ret[i] = (ret[i - 2] & ~ret[i - 1] | (ret[i - 6] >> (i - 4))) & ~(ret[i - 6] >> (i - 2) << (i - 5));
        else if (i == 8)
            ret[i] = (~ret[i - 7] & ret[i - 2]) | ret[i - 3] | ret[i - 3] << (i - 7);
        else if (i == 10)
            ret[i] = ret[i - 9] & ~(ret[i - 5] >> (i - 5));
        else if (i == 11)
            ret[i] = ret[i - 6] | ((ret[i - 1] & ret[i - 3]) >> (i - 5));
        else
            ret[i] = i - i;
    }

    memcpy(ret + 3, ret + 2, 1);
    memcpy(ret + 9, ret + 3, 1);
    memcpy(ret + 7, ret + 4, 1);

    ret[12] = 0;
    printf("%s", ret);
    free(ret);
    return 0;
}

Wait, that for loop we added there could be written in an even more convoluted way! Let’s do so:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

volatile unsigned int a = 0 - 1;
volatile u_int8_t * z = NULL;

int main() {
    switch(a) {
        case 0 - 1:
            z = aligned_alloc(sysconf(_SC_LEVEL1_DCACHE_LINESIZE), 1 * 10 + 3);
            break;
        case 1 * 10 + 3:
            memcpy(z + 3, z + 2, 1);
            memcpy(z + 9, z + 3, 1);
            memcpy(z + 7, z + 4, 1);
            printf("%s", z);
            free(z);
            return 0;
        default:
            z[a] = a == 0 ? z[a] = (1 << (a + 6)) | (1 << (a + 3)) : a == 1 ? (z[a - 1] & (1 << (a + 5))) | (z[a - 1] >> a) | (z[a - 1] >> (a + 5))  : a == 2 ? z[a - 2] | z[1] & ~(z[a - 2] >> (a + 4)) : a == 4 ? z[a - 2] | z[a - 3] | (z[a - 4] >> (a + 1)) : a == 5 ? (z[a - 4] & z[a - 3] & z[a - 5]) >> (a - 4) : a == 6 ? (z[a - 2] & ~z[a - 1] | (z[a - 6] >> (a - 4))) & ~(z[a - 6] >> (a - 2) << (a - 5)) : a == 8 ? (~z[a - 7] & z[a - 2]) | z[a - 3] | z[a - 3] << (a - 7) : a == 10 ? z[a - 9] & ~(z[a - 5] >> (a - 5)) : a == 11 ? z[a - 6] | ((z[a - 1] & z[a - 3]) >> (a - 5)) : a - a;
    }

    a = a + 1;
    main();
}

Well, our switch there is taking quite a bit of space, isn’t it? Let’s fix that and clean up the code a bit:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

volatile u_int8_t a = 0 - 1;
volatile u_int8_t * z = NULL;

int main() {
    a==0-1?z=aligned_alloc(sysconf(_SC_LEVEL1_DCACHE_LINESIZE),1*10+3):a!=1*10+3?z[a]=a==0?z[a]=(1<<(a+6))|(1<<(a+3)):a==1?(z[a-1]&(1<<(a+5)))|(z[a-1]>>a)|(z[a-1]>>(a+5)):a==2?z[a-2]|z[1]&~(z[a-2]>>(a+4)):a==4?z[a-2]|z[a-3]|(z[a-4]>>(a+1)):a==5?(z[a-4]&z[a-3]&z[a-5])>>(a-4):a==6?(z[a-2]&~z[a-1]|(z[a-6]>>(a-4)))&~(z[a-6]>>(a-2)<<(a-5)):a==8?(~z[a-7]&z[a-2])|z[a-3]|z[a-3]<<(a-7):a==10?z[a-9]&~(z[a-5]>>(a-5)):a==11?z[a-6]|((z[a-1]&z[a-3])>>(a-5)):a-a:0;if(a==1*10+3){memcpy(z+3,z+2,1);memcpy(z+9,z+3,1);memcpy(z+7,z+4,1);printf("%s",z);free(z);return 0;}a=a+1;main();
}

And there we go - a program that prints Hello World , in just a single line of logic!

I’m sure there’s more ways to improve the unreadability of the project, so if you see something that could be improved, please let me know!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Redis 深度历险:核心原理与应用实践

Redis 深度历险:核心原理与应用实践

钱文品 / 电子工业出版社 / 2019-1 / 79

Redis 是互联网技术架构在存储系统中使用得最为广泛的中间件,也是中高级后端工程师技术面试中面试官最喜欢问的工程技能之一,特别是那些优秀的互联网公司,通常要求面试者不仅仅掌握 Redis 基础用法,还要理解 Redis 内部实现的细节原理。《Redis 深度历险:核心原理与应用实践》作者老钱在使用 Redis 上积累了丰富的实战经验,希望帮助更多后端开发者更快、更深入地掌握 Redis 技能。 ......一起来看看 《Redis 深度历险:核心原理与应用实践》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具