[C언어 기초 CURSE] Hello, World 출력하기

일반적으로 프로그래밍을 배울 때는 C언어부터 시작하고, (요즘은 python부터라지만) C언어를 제일 처음 배울 때 접하는 코드는 바로 그 유명한 'Hello, world!'를 출력하는 코드다. 오늘은 그 코드를 출력하는 방법들에 대해 알아보자.

1번 : 근본

#include <stdio.h>

main()
{
    printf("hello, world\n");
}

해설

K&R의 <The C Programming Language>에서 제일 처음 등장하는 근본 있는 코드라고 할 수 있다.

C언어는 코드가 본격적으로 실행되면 main() 함수 내부에 있는 코드를 우선적으로 실행한다. 내부의 printf 함수는 문자열을 인자로 받아 출력하므로 "hello, world\n"라는 문자열을 전달해주면 hello, world가 출력된다.

2번: hello world 없는 hello world 코드(1)

#include <stdio.h>

int main() {
    unsigned a[3] = { 560229490, 1867980911, 1819043144 };
    int i = 2;
    do {
        do {
            putchar(a[i] & 255);
        } while ( a[i] >>= 8 );
    } while(i--);
}

해설

해당 코드는 i가 2부터 1씩 줄어들면서, 배열 a[3]에 있는 각각의 요소를 255로 나눈 나머지 값(마지막 8비트)에 대해 해당하는 문자를 출력하고, 이후 a[i]에 대해 비트 시프트 연산을 수행하여 그 다음 8비트에 대해 같은 과정을 수행한다. 560229490, 1867980911, 1819043144는 16진수로 변환하면 각각

  • 21646C72
  • 6F57206F
  • 6C6C6548

가 되고, 마지막 8비트씩 호출되는 순서대로 끊어서 써보면 48 65 6C 6C 6F 20 57 6F 72 6C 64 21이고, 각각 대응되는 ASCII 문자로 표현하면 Hello World!가 된다.

3번 : hello world 없는 hello world 코드(2)

이쯤 되면 알겠지만 제목의 curse는 course의 오타가 아니였다. 우린 지금 기초 curse를 살펴보고 있다.

int main() {
    // Some floating point numbers for testing
    float b[] = {1.1431391224375825e+27, 6.6578486920496456e+28, 7.7392930965627798e-19, 3.2512161851627752e-9};
    // Print all numbers in array b[]
    puts(b);

    return 0;
}

해설

컴파일 타임에 b를 초기화 하면서 Hello, World!를 littel endian으로 표현한 값이 들어가도록 숫자들을 적어둔 코드다. IEEE 754에 맞추어 주어진 값들을 HEX로 나타내면 Hello, World! 임을 알 수 있다.

4번 : GREET PLANET

외계인이 지구에 처음 오면 무슨 말을 할까? hello world!

#include <stdio.h>
main() {
  long long P = 1,
            E = 2,
            T = 5,
            A = 61,
            L = 251,
            N = 3659,
            R = 271173410,
            G = 1479296389,
            x[] = { G * R * E * E * T , P * L * A * N * E * T };
  puts((char*)x);
}

해설

이건 long long int로 표현했을 뿐, 원리는 앞선 3번 예시와 같다.

5번 : ?

이젠 사람의 언어로 표현할 수 없는 코드다.

#include <stdio.h>
#define o stdout
#define p fputs
int main(_){int*I=&_,_I=2113,l1=3271;_=14557;_I*=503;_<<=3;_*='=';_I<<=0==0;_I=7*'Y'*853<<2;
p(I,o);I=&_I;p(I,o);I=&_;

    _+= l1*11*11;

_I += 0xF5<<8;p(I,o);I=&_I;p(I,o);}

해설

복잡해보이게 여러 특수문자들을 섞어놨지만 원리는 앞선 것들과 같다.
각 변수들의 값이 어떻게 변하는지 유의하며 코드를 살펴보자.

6번 : ????

이게)무(슨)코드)인지(해(석())도(못)(하겠)다)

#define u unsigned char
#define v while(*x)
#define z(x) putchar(*x);
#define y(x) ++*x;
#define p(x) ++x;
#define e(x) --*x;
#define d(x) --x;
#define w(x) x x
main(){u *x=calloc(12,1);u *l=x;w(w(w(y(x))))w(y(x))v{p(x)w(w(y(x)))w(y(x))y(x)p
(x)w(w(w(y(x))))w(y(x))p(x)w(y(x))y(x)p(x)w(w(w(y(x))))y(x)w(w(d(x)))e(x)}p(x)w(
y(x))z(x)p(x)y(x)z(x)w(w(y(x)))w(y(x))y(x)w(z(x))w(y(x))y(x)z(x)p(x)w(y(x))z(x)p
(x)w(e(x))e(x)z(x)w(d(x))z(x)w(y(x))y(x)z(x)w(w(e(x)))w(e(x))z(x)w(w(w(e(x))))z(
x)p(x)y(x)z(x)free(l);}

해설

하아… define들을 다 풀어 놓으면 다음 코드와 같다.

main(){unsigned char *x=calloc(12,1);unsigned char *l=x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x;
    while(*x){
        ++x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++x; ++*x; ++*x; ++*x; ++x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; --x; --x; --x; --x; --*x;
    } 
    ++x; ++*x; ++*x;
    putchar(*x);
    ++x; ++*x;
    putchar(*x); ++*x; ++*x; ++*x; ++*x; ++*x; ++*x; ++*x;
    putchar(*x);
    putchar(*x); ++*x; ++*x; ++*x;
    putchar(*x); ++x; ++*x; ++*x;
    putchar(*x); ++x; --*x; --*x; --*x;
    putchar(*x); --x; --x;
    putchar(*x); ++*x; ++*x; ++*x;
    putchar(*x); --*x; --*x; --*x; --*x;--*x; --*x;putchar(*x); --*x; --*x; --*x; --*x; --*x; --*x; --*x; --*x;
    putchar(*x); ++x; ++*x;
    putchar(*x);
    free(l);}

포인트*x를 커서로 두고 while문으로 할당한 배열의 마지막으로 커서를 옮긴다. 그 후 뒤에서부터 ascii code에 맞는 값을 설정하고, 한 글자를 출력하고, 그 다음칸에서 같은 과정을 반복하면서 Hello World!를 출력한다.

7번: 저 집에 갈래요

집에 가고 싶어졌다.

#include <stdio.h>
#define $ __func__
int main() {
    printf("%c%c%c%c%c%c%c%c%c%c%c%c", ($[0]-$[($[3]-$[0])+($[3]-$[0])])*(($[0]-$[($[3]-$[0])])+($[0]-$[($[3]-$[0])+($[3]-$[0])])+($[3]-$[0])+($[3]-$[0])), ($[3]-$[($[3]-$[0])+($[3]-$[0])])*($[3]-$[($[3]-$[0])+($[3]-$[0])])*($[0]-$[($[3]-$[0])+($[3]-$[0])])+($[3]-$[0]), ($[0]-$[($[3]-$[0])])*(($[0]-$[($[3]-$[0])+($[3]-$[0])])+($[3]-$[($[3]-$[0])+($[3]-$[0])])), ($[0]-$[($[3]-$[0])])*(($[0]-$[($[3]-$[0])+($[3]-$[0])])+($[3]-$[($[3]-$[0])+($[3]-$[0])])), $[($[3]-$[0])+($[3]-$[0])+($[3]-$[0])]+($[3]-$[0]), ((($[0]-$[($[3]-$[0])])+($[0]-$[($[3]-$[0])+($[3]-$[0])]))*($[0]-$[($[3]-$[0])+($[3]-$[0])]))>>($[3]-$[0]), ($[0]-$[($[3]-$[0])])+($[0]-$[($[3]-$[0])])/($[0]-$[($[3]-$[0])+($[3]-$[0])])*($[3]-$[($[3]-$[0])+($[3]-$[0])])*($[3]-$[($[3]-$[0])+($[3]-$[0])]), $[($[3]-$[0])+($[3]-$[0])+($[3]-$[0])]+($[3]-$[0]), $[($[3]-$[0])+($[3]-$[0])+($[3]-$[0])]+($[0]-$[($[3]-$[0])+($[3]-$[0])]), $[0]-($[3]-$[0]), $[($[3]-$[0])]+($[0]-$[($[3]-$[0])+($[3]-$[0])])-($[3]-$[0]), (($[0]-$[($[3]-$[0])])-($[3]-$[0]))*(($[3]-$[($[3]-$[0])+($[3]-$[0])])-($[3]-$[0])-($[3]-$[0])));
}

해설

__func__는 C++11에 추가된 표준으로, 호출된 함수의 이름을 문자열로 반환한다. 즉, 이 코드는 main 이라는 문자열을 지지고 볶아서 Hello, World! 로 만들어낸 것이다.

레퍼런스

  1. The C Programming Language
  2. https://codegolf.stackexchange.com/questions/22533/weirdest-obfuscated-hello-world
  3. https://www.facebook.com/groups/System.out.Coding/posts/4618578478201811/

글을 쓰기 위한 원동력을 얻기 위해 자발적인 후원을 받고 있습니다.
후원해 주신 분들께는 뉴스레터를 통해 일부 컨텐츠가 선공개될 예정입니다.
(구독자 이름과 후원자 이름이 동일해야 발송이 가능합니다)