안녕하세요. 한주동안 잘지내셨는지요?^ ^;
오늘은 Hello World를 출력하는(?) 화면을 만들어 볼 생각입니다. ^ ^
모든 Programming 언어의 책의 첫장을 보면 화면에 Hello World를 띄우는 것부터 연습를 하죠? ^ ^; 그래서 저도 오늘은 Hello World를 화면에 보여주려고 합니다. 가장 기초적인 부분부터 뼈대를 만들어 가볼까요? ㅋㅋㅋ
이번에는 Source를 분석할때는 시그널(이벤트) 함수와 시그널 핸들러 함수에 대해서 집중적으로 설명해 볼까 합니다.
1. Hello World를 들어가기에 앞서..
이번에는 여태까지 내용과는 달리 중요한 부분이 몇가지 나오는 것 같아요. 중요한 부분이라면, gtk프로그래밍에서 interface를 다루는 부분이죠. interface란 사용자와 컴퓨터(or 윈도우) 사이의 관계를 말하며, 사용자가 요구하는 대로 반응하는 환경을 구현하는 것이 interface 프로그래밍이라고 합니다.
어떤 식으로 Hello World를 출력해 볼까요? 일단, 버튼과 label을 하나 만들어 볼까해요~ 버튼을 누르면 label의 내용이 "Hello World Open"으로 바뀌었다가 다시 한번 더 누르면 "Hello World Closed"로 바꾸도록 만들어 보겠습니다. 그럼 여기서도 알 수 있듯이 오늘은 버튼을 누름에 따라 변화를 구현하는부분이 핵심이라는 것을 알 수 있죠?
2. Hello World
#include <gtk/gtk.h>
GtkWidget *label;
void button_clicked ( gtkwidget *widget, gpointer data)
{
static int toggle = 1;
if (toggle == 1)
{
gtk_label_set_text ( gtk_label(label) , "hello world opened");
toggle = 0;
}
else
{
gtk_label_set_text ( gtk_label(label) , "hello world closed");
toggle = 1;
}
}
void delete_event ( gtkwidget *widget, gdkevent *event, gpointer data)
{
gtk_main_quit ();
}
int main( int argc,char *argv[] )
{
gtkwidget *window, *button;
gtkwidget *vbox;
gtk_init (&argc, &argv);
window = gtk_window_new (gtk_window_toplevel);
gtk_window_set_title(gtk_window (window), "upgrade hello world");
gtk_signal_connect ( gtk_object(window), "delete_event",
gtk_signal_func ( delete_event), null);
gtk_container_set_border_width ( gtk_container ( window), 10 );
vbox = gtk_vbox_new ( false,0);
gtk_container_add ( gtk_container ( window ), vbox);
label = gtk_label_new ("hello world closed");
gtk_box_pack_start (gtk_box(vbox), label, true, true, 0);
gtk_widget_show ( label);
button = gtk_button_new_with_label ("Click");
gtk_signal_connect ( gtk_object (button), "clicked");
gtk_signal_func ( button_clicked ), null);
gtk_box_pack_start (gtk_box(vbox), button, true, true, 0);
gtk_widget_show (button);
gtk_widget_show (vbox);
gtk_widget_show (window);
gtk_main ();
return(0);
}
3. Hello World Source 설명
main()을 보면 보지못했던 새로운 함수들이 보이죠?
gtk_window_set_title();
gtk_signal_connect();
gtk_container_set_border_width();
gtk_vbox_new();
gtk_button_new_with_label();
gtk_box_pack_start();
gtk_window_set_title();
위의 함수는 메인 윈도우의 제목을 정해 주는 부분입니다. title!! 이 글자만 봐도 대충 감이 잡히죠? ^ ^;
gtk_container_set_border_width();
이 함수는 window 의 border 의 크기를 정의합니다.
gtk_vbox_new();
gtk에서 윈도우 안의 여러가지 위젯들을 배열하기 위해서 box라는 위젯을 많이 씁니다. gtk는 window 안에 window를 삽입 할 수 가 없어서 이러한 도구를 앞으로도 많이 사용할 것입니다. table과 frame이 주로 사용되는 도구들 중의 하나이죠 ^ ^
box는 실제로 보여지는 위젯은 아니지만 다른 widget들을 배열하기 위해 사용하지요. box인데 vbox라고 사용한 것에 대해 의심이 가지 않아요? box는 두가지 종류가 있습니다. vbox와 hbox가 사용됩니다. 이것은 수직박스와 수평박스를 나타내지요. 물론 gtk_*_new()으로 정의할 수 있습니다. hbox와 vbox의 조합으로 위젯의 위치를 정해서 좀더 직관화된 인터페이스를 만들 수 있죠.
위의 "Hello World" source는 vbox를 정의하고 그곳에 레이블과 버튼을 올려놓습니다(packing). packing이라는 말은 widget들을 쌓아 넣는다고 보면됩니다. 예를들어 커다란 여행 가방에 여러가지 물품들을 차곡차곡 정리해야 한다면 vbox로 나눈뒤 수직 방향의 박스에 차곡차곡 widget을 넣어서 보기좋게 정돈되는 과정이라고 생각하시면 되죠 ^ ^ 머리속으로 그림을 그리면 좀더 쉽게 이해가 되실 겁니다.
gtk_button_new_with_label();
button을 정의하는데 label을 넣고 싶을 때 쓰는 함수입니다. 버튼에는 일반적으로 label이 보여서 사용자에게 어떤 역할을 하는지 알려주는 역할을 하죠.
gtk_box_pack_start();
gtk_container_add와 비슷한데.(기억나시죠? container에 무언가 추가하는^ ^;) 여기서는 박스에 쌓기(packing) 위해서 위 함수를 쓴다. gtk_box_pack_start()는 hbox 위젯의 왼쪽에서 오른쪽, vbox부분에서는 위쪽에서 아래쪽의 순으로 쌓는다는 의미이며, 반대 역할을 하는 gtk_box_pack_end()함수도 있습니다. 뒤에 붙는 인자들은 expand, fill할 것인가에 대한 선택이며, 마지막이 padding의 크기를 정의합니다.
이제부터.. 가장 중요한 부분을 설명해 보겠습니다. 제가 처음에 말씀드렸죠. 오늘은 가~장 중요한 무언가가 나올것이라구요.
이제 나타날 때가 되었습니다. 짜~~~잔!!!^ ^*
gtk_signal_connect( gtkobject *object,
gchar *name,
gtksignalfunc func,
gpointer func_data
);
위 함수는 interface , 즉 사용자가 뭔가를 행하였을(signal) 때 반응 하는 함수에 대해서 연결 (connect ) 시켜주는 역할을 합니다.
위의 예제(Hello World)중에서..
gtk_signal_connect ( gtk_object (button),
"clicked",
gtk_signal_func ( button_clicked ),
null);
예로 들자면, 사용자가 button이라는 위젯을 눌렀(click)을 경우 'clicked' 라는 이벤트가 발생하며, button_clicked라는 함수를 불러 실행하라는 의미가 됩니다. 실제 button_clicked는 소스의 윗부분에 정의하였습니다.
두 번째 인수인 "clicked"는 임의로 정해지는 것이 아닙니다. 이것은 각각의 위젯에 대해서 사용자가 행한 행동 (event라고도 할수 있다)을 말하며, 버튼이라면 누르는 것이 있을 것이며, 메뉴에서는 선택하는 부분등이 예가 될 수 있습니다. 이 event는 각각의 위젯에 따라 다르며, 그 이름또한 틀립니다. 그 이름은 미리 정의되어 있습니다. 물론 사용자가 임의의 위젯을 만들고 임의의 이벤트를 만들수는 있지만, 그것은 좀더 고차원적인 기술이기에 다음 기회에 해보아야겠습니다.
사용자가 버튼을 눌렀더니, button_clicked이라는 함수가 불러집니다. 실제 위 소스에서는 버튼이 눌러지면 label 의 내용을 토글시키는 작용을 하게 해놓았습니다. c 프로그래밍을 접한 우리들은 쉽게 접근할 수 있겠죠. 여기에서 마지막 인수는 함수에 넘겨질 데이터입니다. 이 데이터는 대부분 프로그래밍에서는 null이지만 사용자가 필요에 의해 임의의 값을 넘겨주어야 할 때 적어주면 됩니다.
위에 또다른 gtk_signal_connect가 있죠? 'delete_event' 이며 이는 시스템 버튼 (오른쪽 위의 x모양의 버튼) 이 눌러졌을 경우 gtk 내부에 미리 정의된 기본 함수, gtk_main_quit을 부르게 되어 있습니다. 단순히 윈도우를 종료시키는 함수죠. 사용자가 만들지 않아도 되는 (일반적인 이벤트 함수) 함수들은 미리 정의된 것들을 쓰기도 합니다.
그럼. 정리를 해볼까요? ^ ^;
(1) 우선 window을 생성하고, 박스를 만듭니다.
(2) label을 생성하고 초기 이름은 'hello world closed'이고 이것을 박스에 쌓아봅니다(packing).
(3) button을 만들고 초기 label은 '클릭해 주세요'이며, 버튼이 눌러질 경우 행하여질 이벤트 함수를 'button_clicked'라고 정의하였고 이벤트와 연결하였습니다. 버튼 또한 box에 packing시킵니다.
(4) 각각의 위젯을 보이게 합니다.
4. 결과 화면
오늘 저의 설명은 어떠하였는지요? ^ ^; 궁금한 사항이 있으면 댓글을 달아주세요 ^ ^
무언가 하나씩 해나아가는 듯한 느낌이 들지 않아요? ㅋㅋ 오늘은 무언가 설명 좀 한것 같아서 나름 뿌듯한걸요? ^ ^;
함수를 좀더 쉽게 설명하기 위해 책과 블로그들을 참고하였는데, 아직 많이 미흡-_-+ 이쁘게 봐주세요 ^ ^
GCC는 (GNU Compiler Collection)의 약자이다. GNU C Compiler라고 부르기도 하는데 GCC가 C++, JAva, Fortran, Ada등 많은 프로그래밍 언어를 지원하면서 부터 단순히 C Compiler라고 부르기보다는 전자의 경우가 맞을 것이라 생각한다.
GCC의 가장 큰 장점은 현존하는 수많은 Architecture의 지원이다. x86부터 시작하여 ARM, MIPS, PowerPC, Sparc등등 현존하는 대부분의 아키텍쳐를 지원한다. 이렇게 많은 아키텍쳐를 지원할 수 있었던 것은 각 아키텍쳐로의 포팅이 용이하게 구성되어져 있기 때문이다. 따라서 새로운 아키텍쳐를 GCC에 포팅하는 일도 간단하지는 않겠지만 새로운 컴파일러를 제작하는것에 비해 상당한 수고를 덜 수 있을 것이다.
그럼 간단히 GCC의 컴파일 과정을 알아보자.
소스파일(.c) ->> 전처리후 파일(.i) ->> 어셈블리 파일(.s) ->> 오브젝트 파일 (.o) ->> 최종 실행파일(ELF)
(전처리과정) (컴파일과정) (어셈블러과정) (링킹과정)
이것이 보통 gcc가 컴파일 되는 과정이다.
gcc로 보통 -o 옵션을 주게 되면 각 단계별로 생성되는 파일을 최종 ELF실행을 만들어 낸후 다 삭제 해 버린다. 중간 생성 파일들을 보기위해서는
gcc -E 옵션을 주면 .i파일을 볼 수 있고 -S 옵션을 주면 .s파일을 생성하며, -c 옵션을 주면 .o파일을 만들어내게 된다. 이것 모두를 다 보고 싶다면 --save-temps 옵션을 주게 되면 중간생성 파일들을 보두 볼 수 있다.
컴파일러는 단순히 고레벨 수준의 언어를 최종 아키텍쳐의 목적코드로 만들어내는데에 그 역할이 있지 않다. 현대 컴파일러에서 가장 중요한 부분은 최적화 부분이다. 사용자가 작성한 코드가 해당 아키텍쳐에서 최적으로 동작하게끔 목적코드를 생성해 주어야 한다. 그래야 프로그램의 성능을 극대화 시킬 수 있다. 그 과정이 .i 에서 .s로의 컴파일과정에 일어나게 된다.
이과정은 크게 4가지로 나뉘어 지는데
GENERIC tree -> GIMPLE tree -> SSA -> RTL
이런순서대로 GCC는 해당 소스파일을 여러단계에 걸쳐 최적화를 이루어내게 된다.
크게 최적화는 두가지 부류로 나누어 볼 수 있는데 컴퓨터 아키텍쳐에 종속적인 최적화와 그렇지 않은 최적화로 나누어 볼 수 있다. RTL전 까지는 아키텍쳐에 비종속적인 최적화가 일어나고 RTL변환후에는 아키텍쳐 종속적인 최적화가 이루어지게 된다.
보통 학부 컴파일러 과정에서는 파싱(토큰, 문법체크)과 의미분석(타입체크 등등)과정까지만 배우고 만다. 이런 부분을 front-end라고 부르고 그 뒤의 최적화 부분을 back-end라고 부른다. front-end는 이미 많은 해결책과 거의 최적화된 솔루션이 존재해 현재 연구분야에서는 거의 제외되고 있다고들 하고, 최적화 부분인 back-end가 주요 관심사라고 한다.( 생각해보면 컴퓨터 아키텍쳐의 발전에 따라 계속 고려되어야 하는 부분이니 계속 연구의 수요는 일어날 것이라 생각된다. )
여튼 학부과정에서 배운 파싱과정을 거쳐 파싱트리가 만들어지면 이것을 프로그래밍 언어에 독립적인 general한 트리로 만들게 된다. 이것이 바로 GENERIC 트리이다. 이후에 아키텍쳐 비종속적인 최적화를 이루기 위해 트리를 좀더 변경시키는데 이것이 GIMPLE 트리에 해당한다. GIMPLE 트리에서 한단계 더 변형을 가하는데 이것이 바로 SSA(Static Single Assignment)형태이다.
이렇게 아키텍쳐 비종속적인 최적화를 수행한후에 거의 어셈블리 형태와 유사한 RTL( Register Transfer Language)로 변환한후 여기서 아키텍쳐 종속적인 최적화를 수행하게 된다. ->각 트리에 대한 얘기는 추후에....
오실로스코프의 대역폭
![]() ![]()
|
1. 오실로스코프 아날로그 대역폭(Analog Bandwidth)은 입력되는 정현파의 진폭이 -3dB
(대략 30%) 저하되는 지점의 주파수로 정의 합니다.
2. 오실로스코프의 대역폭별 50 MHz 구형파 신호의 재생
3. 구형파나 펄스파와 같이 빠른 상승 또는 하강 시간을 갖는 신호를 측정시 다량의 고주파
성분을 포함하고 있어 신호의 반복 주기만을 감안한 스코프 대역폭 선택은 의미가 없을 수
있습니다. 따라서, 신호의 주파수 보다 높은 대역폭을 갖는 스코프를 사용하여야 합니다.
* 오실로스코프의 신호대비 낮은 대역폭으로 인한 영향
- 신호의 상승/하강 시간이 길어진다.
- 신호의 진폭을 감소 시킨다.
* 오실로스코프의 대역폭 계산법