컴파일러

C언어는 컴파일러를 필요로 한다. 아무리 멋진 프로그램을 만들어라도 컴파일을 해야 작동한다. C언어를 컴파일 해줄 수 있는 컴파일러는 여러가지가 있는데, 이에 따라 C언어의 종류를 나눌 수 있다. 컴파일러를 만드는 회사는 여러곳이 있는데, 볼랜드의 Turbo C, 마이크로소프트의 MS C, 인텔의 Intel C complier, 그리고 GPL에 따라 자유롭게 쓸 수 있는 GNU C가 있다. 컴파일러의 실행화일 이름은 C complier를 따서 cc로 되어 있고, 각각 앞에 자기네 회사 첫 글자를 따서 tcc, mcc, icc, gcc등등으로 부른다.

물론, 난 리눅스에서 기본적으로 자유롭게 사용할 수 있는 gcc를 기준으로 설명할 것이다. 다른 컴파일러들 사용하는 것도 그다지 어렵지는 않다. 컴파일러의 설치는 알아서 다들 해 보시기 바란다.

컴파일하는 방법은 아주 쉽다. 예를들어, example.c라는 프로그램을 만들었다고 하자. example.c는 메모장에서 열어보면 그냥 생으로 보이는, 아직 요리가 되지 않은 날것이다. 이것을 컴퓨터의 메모리 속에 쑤셔넣기 위해서는 바이너리로 바꿔줘야 하는데, 그렇게 하려면 다음과 같이 명령하면 된다.

gcc example.c

그럼 a.out이라는 파일이 거기에 새로 생성될 것이다. 이제 a.out을 실행시키면 된다. 실행 방법은, 리눅스의 경우에는 ./a.out 이라고 해야 한다. 윈도우는 뭐 그냥 두번 클릭하면 되겠다. 하지만 맨날 a.out만 만들 수는 없잖은가. 그럼 목적지를 얘기해 주면 된다.

gcc example.c -o example

이렇게 하면 -o 뒤에 있는 파일 이름으로 컴파일 되어 출력된다.

다른건 그다지 어려운게 없는데, 만약 수학 함수 헤더인 math.h를 include해서 컴파일 할 경우에는 에러가 뜰 것이다. 이 경우, link math 옵션을 붙여야 한다. 이것때문에 괜히 삽질하는 경우가 많다.

gcc example.c -o example -lm

그럼 에러가 안나올 것이다.

C언어 프로그램을 컴파일 할 때 나오는 에러는 전부 의미가 있는 내용으로, 부디 에러가 아무것도 없는 프로그램을 만들 수 있기를 바란다.

아래는 gcc –help 명령을 쳤을 때 나오는 내용이다.

Usage: gcc [options] file…

Options:

-pass-exit-codes Exit with highest error code from a phase

–help Display this information

–target-help Display target specific command line options

(Use ‘-v –help’ to display command line options of sub-processes)

-dumpspecs Display all of the built in spec strings

-dumpversion Display the version of the compiler

-dumpmachine Display the compiler’s target processor

-print-search-dirs Display the directories in the compiler’s search path

-print-libgcc-file-name Display the name of the compiler’s companion library

-print-file-name= Display the full path to library
-print-prog-name= Display the full path to compiler component
-print-multi-directory Display the root directory for versions of libgcc

-print-multi-lib Display the mapping between command line options and

multiple library search directories

-print-multi-os-directory Display the relative path to OS libraries

-Wa, Pass comma-separated on to the assembler

-Wp, Pass comma-separated on to the preprocessor

-Wl, Pass comma-separated on to the linker

-Xassembler Pass on to the assembler

-Xpreprocessor Pass on to the preprocessor

-Xlinker Pass on to the linker

-combine Pass multiple source files to compiler at once

-save-temps Do not delete intermediate files

-pipe Use pipes rather than intermediate files

-time Time the execution of each subprocess

-specs= Override built-in specs with the contents of

-std= Assume that the input sources are for

–sysroot= Use as the root directory for headers

for headers and libraries

-B Add to the compiler’s search paths

-b Run gcc for target , if installed

-V Run gcc version number , if installed

-v Display the programs invoked by the compiler

-### Like -v but options quoted and commands not executed

-E Preprocess only; do not compile, assemble or link

-S Compile only; do not assemble or link

-c Compile and assemble, but do not link

-o Place the output into

-x Specify the language of the following input files

Permissible languages include: c c++ assembler none

‘none’ means revert to the default behavior of

guessing the language based on the file’s extension

Options starting with -g, -f, -m, -O, -W, or –param are automatically

passed on to the various sub-processes invoked by gcc. In order to pass

other options on to these processes the -W options must be used.

이게 정확히 뭔얘기인지는 나도 잘 모르겠다. 다만, 프로그램을 복잡하게 만들수록 위의 옵션들을 사용하게 될 일이 있을테니, 만약 프로그램이 완벽한데 컴파일이 이상하게 된다면 옵션을 잘 살펴볼 일이다.

삶에 중독된다

모든 인간이 중독된 것, 삶.

반드시 가져야만 하고, 구하기도 쉽고, 끊을 수 없으며, 만약 끊는다면 그것으로 이미 죽음을 맞이해야만 하는 것. 바로 삶이다.

새해를 맞이하면서, 삶에 중독되어 습관적으로 나이를 먹고 있는건 아닌지 생각해 보았다.

군 복무 기간 단축

난 아직 군대에 갔다오지 않았다. 따라서, 최근 노무현 대통령의 발언을 액면 그대로 믿는다면 난 노빠가 될지도 모른다.

한 6개월 줄여서 18개월로 만든다고 한다. 여기에 대해, 주성영이라는 아저씨가 차라리 군 가산점 제도를 부활시키라고 주장한다. 아마 이건 여성가족부에서 반대할 것이다. 생각해보자. 군 가산점 제도를 없앤 것은 남녀차별을 없애기 위해서다. 물론 이런 얘기를 하려면 여성도 2년간 번 소득중에 병장 월급에 준하는 10만원 정도만 남기고 나라에 갖다 바치라는 얘기가 나올지도 모르지만 말이다.

아무튼, 명백한건 군대를 가지 않은 남자들에게는 군 가산점보다 군 복무기간 단축이 훨씬 매력적인 떡밥이라는 것이다. 물론 나 역시 군 가산점보다 복무기간 단축을 훨씬 선호한다. 왜? 난 군 가산점을 쓸 일이 없을 테니까. 공무원은 내 장래희망에 해당하지 않는다.

C언어 기본 문법

C언어는 언어다. 따라서 문법이 있다.

모든 명령문은 ;으로 끝나야 한다. ;이 없으면 끝나지 않은 것이고, ;이 있으면 무조건 일단 끝난 거다. 엔터나 공백은 모두 한칸으로 처리되고, 아무튼 ;만이 끝을 나타낸다. -_-;

//뭐라고?

한줄짜리 주석. 이거 뒤에 있는 글자들은 그 줄이 끝날 때 까지 전부 무시된다.

/* 어쩌라고 */

여러줄 짜리 주석. 물론 한줄짜리 주석 달 때도 쓸 수 있다. 별표로 둘러싸인 부분의 안에 있는 건 아무리 길더라도 전부 무시된다.

함수는 다음과 같이 사용한다

함수(인자);

이렇게 적어두면, 함수 안에 인자가 들어가서 적당히 처리된다. 인자는 여러개가 될 수도 있는데, 그때는 쉼표를 이용해서 구별한다. 함수 만드는 법은 따로 설명하도록 하겠다.

연산자들 : =, +, -,*, /, %, ++, —

대입연산자”=”는 오른쪽에 있는 걸 왼쪽에 있는 것에다가 집어넣는다.

+,-,*,/는 각각의 양쪽에 있는 것들을 계산해서 그 계산값을 되돌린다. /는 왼쪽에 있는 값을 오른쪽에 있는 값으로 나눈다. %는 왼쪽에 있는 값을 오른쪽에 있는 값으로 나눈 나머지를 찾아준다.

++와 –는 정수에서 1을 더하거나 빼는 연산자이다. 가령 a++;는 a에 1을 더한다. 이건 ++a;라고 쓸 수도 있는데, 둘 사이의 차이는 a++는 일단 a에 있는 값을 다른데다가 쓰고나서 1을 더한다는 뜻이고, ++a는 일단 1을 더한 후에 계산하는데다가 쓴다는 뜻이다. 다른 명령어를 같이 쓰지 않는 경우에는 a++와 ++a는 아무런 차이가 없다.



[각주:

1

]



–연산자는 1을 빼는 작용을 한다.

#include

#include”yyy.yyy”

#include는 지정한 화일을 포함시킨다. 이때, 포함시킨다는 뜻은 말 그대로 “있는 그대로” 집어넣는다는 뜻이다. 프로그램에 xxxxxxx라는 문자열을 적어넣는 것과, xxxxxxx라는 문자열이 포함된 xxx.xxx라는 파일을 include하는 것은 완전히 똑같다. 따라서, include구문은 보통 공통적으로 여러 화일에서 쓰이는 것들을 모아놓고 여기저기서 불러와서 쓸 때 사용한다. 가령, 어떤 함수를 정의했는데 그게 여기저기서 쓸 일이 많다면 헤더화일로 적당히 만들어 놓고서 불러오면 되는 것이다. 그럼 함수가 작동을 안할 때 헤더화일만 고치면 되므로 아주 좋다. 꺽쇠와 따옴표에 차이가 있는데, 꺽쇠는 지정된 화일을 컴파일러가 설치된 기본 라이브러리 위치에서 찾고, 따옴표는 컴파일하는 화일이 있는 위치에서 지정된 화일을 찾는다.

참고로, #이 들어간 명령을 선행처리기(preprocessor)라고 하는데, define, typedef등이 있다.

#define ABCD xxxx

이런식으로 쓰면, 프로그램에서 ABCD라는 구문이 나올 때마다 항상 그것은 자동으로 xxxx로 치환된다. 가령, 원주율을 3.1이라고 알고 있다가, 좀 더 정확한 계산을 해서 3.14라는 걸 알았다면, 모든 곳에서 3.1을 3.14로 고칠 필요 없이, 애초에 #define PI 3.1로 해 놓고 PI로 모든 원주율을 계산한 후에, 나중에 첫줄만 3.1 대신에 3.14로 고치면 된다는 것이다.

참고로 #이 들어간 선행처리기 명령들은 ;를 쓰지 않는 예외사항이다.

;를 쓰지 마라.

괄호의 사용

{}는 구문을 묶을 때 쓴다. 가령, “넌 A도 하고 B도 하고 C도 해야 돼”라고 명령하고 싶은데, 기본적으로 C는 한줄 처리하고나서는 그 다음에 있는 명령만 한다. 그럼 {A; B; C;}라고 쓰면 그게 모두 한 줄로 처리되는 거다. 이건 실제로 써보면 안다.

()는 식을 묶거나 함수에 인자를 넘겨줄 때 쓴다. (a+b)+c는 당연히 a와 b를 먼저 더하고, 그 다음에 c를 더하라는 뜻이 된다. 그리고 function(parameter)형식으로 사용한다는 건 앞서 이야기 했다.

main()

C언어는 함수 위주의 프로그램이다. 따라서, 최초에 실행해야 하는 적어도 한개의 함수는 있어야 하는데, 그게 바로 main함수이다. C언어로 만든 프로그램을 실행시키면 기본적으로 main을 가장 먼저 실행시킨다.

  1. 이런 의미에서 C언어의 확장팩이라고 하는 C++을 왜 이렇게 이름붙였는지 알 수 있다. 아마 C언어를 배우고나서 하나 더 배우라는 뜻 아닐까?

    [본문으로]

구조체

구조체는 뭐냐…

변수 여러개를 묶어둔 것을 의미한다. 원래, C에서 쓸 수 있는 변수 형태는 정수, 실수, 긴 실수 정도인데, 우린 벡터도 써야 하고 복소수도 써야 한다. 이런 경우, 새로운 형태를 지정해 줘야 한다. 사용법은 간단하고 복잡하다.


struct 구조체

{

int x;

int y;

}

이렇게 해 두면 구조체가 선언된다. 그리고 구조체에 있는 값을 다른데서 가져다가 써야 한다면 항상 그 앞에 struct를 붙여줘야 한다. 안그러면 구조체가 구조체라는걸 모르기 때문이다.

실제로 구조체 형태의 변수를 쓸 때는 위와 같이 구조체를 선언해주고, 다음과 같이 사용해야 한다.

struct 구조체 변수이름;

만약 이 변수 안에 있는 x라는 녀석의 값이 필요하면 다음과 같이 불러오면 된다.

변수이름.x

물론 y가 필요하면 점 찍고 y를 쓰면 된다.

아래의 소스는 내가 C언어에서 복소수를 처리하기 위해서 직접 만든 코드이다. 사칙연산, 켤레복소수, 실수부분, 허수부분, 절대값 등을 처리할 수 있게 되어 있다. 한번 분석해 보면 구조체가 어떻게 작동하는지 알 수 있을 것이다.

struct cnumber
{
double x;
double y;
};

//addition
struct cnumber add_cnum(struct cnumber z, struct cnumber w)
{
struct cnumber a={z.x+w.x,z.y+w.y};
return a;
}

//subtraction
struct cnumber sub_cnum(struct cnumber z, struct cnumber w)
{
struct cnumber a;
a.x=z.x-w.x;
a.y=z.y-w.y;
return a;
}

//multiplication
struct cnumber mul_cnum(struct cnumber z, struct cnumber w)
{
struct cnumber a;
a.x=z.x*w.x-z.y*w.y;
a.y=z.x*w.y+z.y*w.x;
return a;
}

//complex conjugate
struct cnumber conj_cnum(struct cnumber z)
{
struct cnumber a;
a.x=z.x;
a.y=-z.y;
return a;
}

//norm
double norm_cnum(struct cnumber z)
{
double a;
z=mul_cnum(z,conj_cnum(z));
a=z.x;
return a;
}

//division : z is divided by w
struct cnumber div_cnum(struct cnumber z, struct cnumber w)
{
struct cnumber a;
a=mul_cnum(z,conj_cnum(w));
a.x=a.x/norm_cnum(w);
a.y=a.y/norm_cnum(w);
return a;
}

//real part
double re_cnum(struct cnumber z)
{
double a;
a=z.x;
return a;
}

//imaginary part
double im_cnum(struct cnumber z)
{
double a;
a=z.y;
return a;
}

//complex phase
struct cnumber phase_cnum(struct cnumber z, double k)
{
struct cnumber x={cos(k),sin(k)};
struct cnumber m=mul_cnum(z,x);
return m;
}

알고리즘

알고리즘은 어떻게 만들까?

난 알고리즘을 만드는 방법을 체계적으로 배운 적은 없다. 다만, 그때그때 필요한 일을 시키기 위해서 컴퓨터의 생각 방식과 나의 생각 방식 사이의 연결 관계를 찾았을 뿐이다. 아마 이 작업을 알고리즘을 만드는 작업이라고 하는 것이라고 생각한다. 프로그램 제작을 직업으로 삼아서 일하시는 분들과 비교하면 아주 허접한 수준이지만, 혹시라도 누군가에게 도움이 될 수도 있다면 그것도 좋지 않을까 해서 몇자 적어둔다. 만약 틀린 부분이 있다면 지적해도 좋다.

앞서 얘기한바와 같이, 컴퓨터가 생각하는 것과 내가 생각하는 것 사이의 연결고리를 찾아내는 것이 알고리즘을 만드는 작업이다. 그렇다면, 일단 두가지를 알아야 한다. 1.컴퓨터가 생각하는 방식과 2.내가 생각하는 방식이다.

1.컴퓨터가 생각하는 방식

컴퓨터의 사고 구조는 단순하다. 숫자들을 아주 많이 늘어놓고서, 그 숫자들을 적당히 골라서 산수 계산을 하고, 그 결과를 저장한다. 그리고 이러한 일을 무작정 반복할 수 있다. 이러한 사실로부터 알 수 있는 몇가지 사실들은 컴퓨터에게 주는 자료는 숫자가 되어야 한다는 것과, 그 숫자로부터 얻을 수 있는 결과들은 역시 숫자가 된다는 것이다. 컴퓨터에게 A+B를 입력해봐야 A와 B가 뭔지 알려주지 않으면 그 출력은 A+B일 뿐이다.

2.내가 생각하는 방식

보편적인 사람이 생각하는 방식은 아주 복잡하다. 사람은 컴퓨터와 달리 논리적인 생각을 한다. 그리고 계산의 지름길을 찾아낼 수 있다. 컴퓨터가 하는 계산이 무조건 미친듯이 반복해서 답을 찾아내는 것이라면, 사람이 답을 찾는 계산은 대충 생각해보고 이미 알려진 사실로부터 답을 유도하는 것이다. 컴퓨터가 생각하는 방식으로는 아직 인간의 증명을 따라가기는 힘들다.

하지만, 사람이 할 수 없는 일들을 컴퓨터에게 시킬 수는 있다. 가령, 10425의 계승을 정확히 계산해 내는 일이라든가 등등. 10425의 계승을 사람보고 계산하라고 시키려면 누구라도 일단 짜증부터 내고 하든가 말든가 할 것이다. 하지만 컴퓨터에게 일을 시키는 것은 쉽다. 프로그램을 만들고 컴파일 한 후에 돌리면 된다.

3.알고리즘

따라서, 내가 얻고 싶은 정보와 입력할 수 있는 정보를 숫자로 나타내는 것이 가장 중요하다. 이러한 이유로, 컴퓨터를 이용해서 푸는 방법을 이용한 것이 바로 수치해석이다. 수치해석은 손으로 풀 수 없거나 풀기 힘들거나 아직 안 풀린 문제들을 당장 활용하기 위해서 근사적인 답을 찾아내는 방법을 제안해 준다. 물론 근사적인 답이라도 얼마든지 실용적으로 활용할 수 있으므로 이 분야는 연구할 가치가 있는 분야가 된다.

가령, 미분방정식을 풀어야 한다면, 찾아야 할 함수를 아주 많은 미지수로 두면 된다. 이러한 미지수들 사이의 관계식이 바로 미분방정식이 되고, 입력하는 숫자들은 바로 초기값이나 경계값이 된다.

4.실제 알고리즘은?

가령, 1부터 100까지 더하는 프로그램을 만든다고 하자

그럼 그 가상 코드는 다음과 같다.

출력(1+2+3+…+100)

자, 이 코드는 허무할 정도로 쉽다. 하지만 100까지 더하는 게 아니라 10000까지 더해야 한다면? 프로그램의 길이가 너무 길어지지 않을까? 입력하다가 차라리 계산하고 싶어질 것이다. 잔머리를 굴려라. 컴퓨터는 산수에 있어서는 아주 끝내주는 녀석이다.

숫자=1

반복(만약 숫자가 100과 같거나 작으면 계속하고, 100보다 크면 그만해라)[합=합+숫자, 숫자=숫자+1]

출력(합)

이러면 좀 짧아졌나? 게다가 원하는대로 100보다 더 많은 숫자를 넣을 때도 고칠 곳이 딱 두군데 뿐이다. 물론 코드의 길이를 더 줄일 수 있는 여지가 있지만, 그건 각자 해 보시라.

컴퓨터 프로그램 언어에는 기본적으로 다음과 같은 명령들이 있다

A=B

이 명령은 B를 A에 대입한다. 정확히는, =의 오른쪽에 있는 녀석이 가진 값들을 왼쪽에 있는 녀석의 값으로 입력해 준다.

만약(조건)[실행문] ; 아니면[실행문] ;

보통은 if ~ else 문으로 주어지는데, 계산을 하다가 멈추거나, 다른 조건들을 대입할 필요가 있을때 등, 아무튼 뭔가 판단할 때 사용할 수 있다.

반복(조건)[실행문]

이건 조건이 맞으면 조건이 틀릴 때 까지 계속 실행문을 반복실행한다. 따라서, 실행문 안에 원하는 만큼 계산을 했으면 조건을 틀리게 만드는 명령을 넣지 않으면 무한루프에 빠져버리게 될 것이므로 조심하자.

+, -, *, /, %

당연히 사칙연산 계산이다 %는 앞에 있는 수를 뒤에 있는 수로 나눈 다음에 그 나머지가 궁금할 때 사용한다.

실제로, 이것만 이용해서도 꽤 많은 것들을 할 수 있다. 가령, 3n+1문제라든가, 조화진동자 문제 등을 해결할 수 있다는 거다.

Hello, world!

Hello, world!

가장 기본적인 영어 문장이다.

누군가에게 인사를 할 때 사용할 수 있으며, 그때는 world 대신에 상대방의 이름을 적으면 된다.

핵공격에 못 견디는 인터넷

기사는 아래 링크 참고.

http://www.inews24.com/php/news_view.php?g_serial=240620&g_menu=020600

이번 지진이 강타한 곳이 해저 케이블 밀집 지역이라고 했다. 전문가가 얘기하기로, 이번 사건으로부터 배울 점이 이 지역에 더 많은 케이블을 설치할 필요가 있다고 한다. 이건 번역을 잘못했거나 이 아저씨가 잘못 얘기했거나 둘 중 하나임이 명백하다. 왜? 지진은 원래 났던데서 계속 일어난다. 그러므로 지진이 난 곳에 케이블이 끊어져서 문제가 됐다면, 그 케이블과 같은 역할을 하는 케이블을 지진이 나지 않은 곳을 경유하도록 연결해야 하는 것이다. 지진때문에 끊어지는 케이블이라면 몇개가 있든지 상관 없이 끊어진다. 인터넷이 핵 공격에도 견딜 수 있다는 얘기는, 우회할 수 있는 경로가 아주 많이 있기 때문에 어느 한 곳의 링크가 깨지더라도 다른 곳을 경유해서 원하는 곳의 정보를 얻을 수 있다는 뜻이다. 이번 사건은 허브와 허브를 연결하는 링크가 깨졌기 때문에 발생한 장애이다. 따라서 이 사고를 막으려면 허브와 허브를 연결하는 링크를 더 많이 만들어야 한다. 하지만 같은 지역에 더 많은 케이블을 설치하는 건 종이위에 연필로 덧칠하는 것과 같다.

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑