[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/

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

Subscribe to jiwon.me

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe