pa 포인터가 하위클래스 객체의 값을 제대로 출력할 수 있는 원리가 궁금합니다.

dltkddyd의 이미지

#include <iostream>
using namespace std;
 
class Parent {
public:
	int num;
	Parent():num(0) {}
	Parent(int  _num):num(_num) {} 
	virtual int get() {
		cout<<"get in Parent"<<endl;
		return num;
	}
	virtual int set(int _num) {
		num=_num;
	}
};
 
class Child:public Parent {
public:
	int length;
	Child():length(0) {}
	Child(int _length):length(_length) {}
	virtual int get() {
		cout<<"get in Child"<<endl;
		return length;
	}
	virtual int set(int _length) {
		length=_length;
	} 
 
};
 
void f(Parent* pa,unsigned int length) {
	for(unsigned int i=0;i<length;i++) {
		cout<<pa[i].get()<<endl;//이 부분을 제대로 이해해야 함.  get() 함수가 가상함수인 것을 알고 동적타입의 단위로 pa가 가리키는 대상
		//체를 나눈다.  그리고 동적결합에 의해 Child의 get() 함수를 호출한다.  
		//이 설명이 맞나요?
                //cout<<pa[i].length<<endl;
                //위 주석 코드는 오류를 유발합니다.  그런데 get함수 앞에 언급한 pa[i]는 오류를 유발하지 않습니다.  
                   //그 이유가 궁금합니다.
	}
 
 
}
 
int main() {
	Child child1(5);//여기서 컴파일이 컴파일하면서 객체의 제일 앞 vptr(클래스에 직접 선언하지는 않았지만)
	//에 가상함수 목록인 vtable의 주소가 저장된다.
	f(&child1,1);
 
	Child child2[3]={Child(7), Child(9), Child(10)};
	f(&child2,3);
 
	return 0;
}

pa->get()에서 length를 제대로 출력하던데요.
pa는 Parent의 주소 또는 Child의 주소를 받을 수 있는데, length를 출력했다는 것은 pa가 Child의 주소를 받았다는 것을 컴파일러가 실행시
이미 알고 있다는 것인가요? 동적 결합이라 하더라도 받을 수 있는 두 가지의 경우가 있는데 어떻게 Child로 알고 length를 호출하나요?
f 함수의 호출부를 보고 pa의 대상체를 Child단위로 나누는 것인가요? 어떻게 슬라이스가 발생하지 않고 length가 제대로 출력되는지 궁금합니다.

이렇게 될까요?

f(&1child2,3);

호출부에서 첫 번재 형식매개변수에 인자가 전달되는 과정은 Parent* pa=&child2 인데, child1의 인스턴스 구조는 다음과 같을 것이고

child2
vptr ----------- vtable 0
int length 1
get n번째 인덱스 n----->이 가리키는 함수를 호출

.........이런 일련의 인스턴스가 연속으로 3개(동적배열)

그래서 child2를 호출하는 것인가요?

만약 정적결합된 상태라면

child2
int length
child2 범주의 get 함수 주소 ---------> get() 함수
Parent::
int num
Parent 범주의 get 함수 주소 ---------> get() 함수

.......이런 일련의 인스턴스가 연속으로 3개(동적배열)

이런 경우에는 vptr이 없는 건지 vptr은 있지만 값이 기본값으로 설정되 있는 건지 확신할 수 없지만 vptr이 없다면 그 없음을 또는 기본값이 설정돼 있음을 기준으로 정적결합임을 식별해서 Child의 단위로 해당 객체에 접근한 다음에 정적타입으로 데이터를 읽어서 Parent 범주의 get 함수에 접근하는 것인가요? 실행시 컴파일이 포인터의 정적타입, 동적타입 모두 사용할 수 있는 것인지 궁금합니다.

익명 사용자의 이미지

f()안에서 pa[1]이 child2[1]을 안 가리킬 것 같은데요.

kukyakya의 이미지

가상 함수가 호출되는 세부 원리에 대해선 구현에 따라 다를 수 있습니다. Itanium C++ ABI (http://mentorembedded.github.io/cxx-abi/abi.html)를 참고하세요.

void f(Parent* pa,unsigned int length);
 
Child child2[3]={Child(7), Child(9), Child(10)};
f(&child2,3);

위의 코드는 사용하지 않는 것이 좋습니다.

pa[i] 는 *(pa + i)와 같고, pa + i 는 (char*)pa + sizeof(pa)*i와 같은데, 위와 같은 경우 pa[1]과 child2[1]은 전혀 다른 곳을 가리키게 됩니다.

==============================================================

내부 구현에 관심이 많으신것 같은데, C++ 보다는 C와 어셈블리를 먼저 심도있게 공부하심이 더 나을 것으로 보입니다.

dltkddyd의 이미지

진도 나가다 보면 되는 것 자체보다 하면 할수록 왜 그런지가 더 궁금해지네요? 그걸 알 수 있는 실력은 부족하고.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

qiiiiiiiip의 이미지


님이 2년 반 전에 작성한 글입니다.
https://kldp.org/node/129340#comment-578428

제3자가 보기에는 현재에도 이 글의 수준에서 조금도 벗어나지 못하고 있습니다.

님의 문제 중 하나는 c++코드를 c처럼 다루고 있는겁니다.
포인터를 다뤄서 memory에 직접 access하고 싶으면 그냥 c를 공부하세요.

님의 더 큰 문제는 현재 실력에 비해 너무 복잡한 잔기술들에 몰두하는 것입니다.
순수한 호기심에 공부하는 것은 좋습니다만,
그 궁극적인 목표는 좋은 프로그램을 짜는 것이 되어야합니다.

좋은 프로그램은 복잡한 기법을 사용한 프로그램이 아니라,
누구나 이해하기 쉬운 코드입니다.

c든 c++이든 java든 좋은 프로그램을 만드는 방법을 공부하시길..

dltkddyd의 이미지

언제 그런 글까지 검색하셨나요. 지금이라면 저런 질문 안 올리겠죠.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

dltkddyd의 이미지

배열식으로 해석하자면 pa[i]는 (Parent*)(pa+i)가 아닌가요? 왜 갑자기 (char*)을 들이대시는지.
(Parent*)(pa+i)라고 했을 때 Child의 가상함수 get()이 제대로 호출되니 그 점이 의아한 겁니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

디스어셈블해서 보세요

익명 사용자의 이미지

프로그래밍 언어 학습을 위해서라면, 좋은 방법이 아닙니다.
디버깅이나 리버스 엔지니어링을 위한 거라면 모르지만요.

프로그래밍 언어라는 추상적 개념중 일부만이 컴파일러라는 구현체로 구체화되는 것이기 때문에
특정 컴파일러의 번역 결과물만 가지고 그걸 디스어셈블해셔 이해하는 것은 한계가 있습니다.

예를 들어, 함수의 매개변수는 스택에 쌓여 전달이 되는 방식으로 구현되기 마련인데,
이걸 디스어셈블로 뜯어보고는 '함수 매개변수는 반드시 뒤에서부터 처리되어 전달된다'라고
생각하는 프로그래머가 많습니다.
근데 사실은 unspecified behavior일 뿐이고, 실제로 ARM 컴파일러 같은 경우는 '가장 까다로운 매개변수'부터
처리합니다.

질문자도 디스 어셈블까진 아니지만 아니지만 그냥 특정 컴파일러만 이리저리 갖고 놀며
자의적으로 해석하다가 고집만 쌓인 결과물이라 할 수 있습니다.
호기심이 많으면 뭐하나요? 그걸 자의적으로 해석해서 잘못된 지식만 잔뜩 쌓았는데.

요샌 귀찮은지 검색도 안하고 그냥 바로 kldp에 올려버리는듯 하더군요.
그리고 설명해주는 사람들과 싸우죠. 왜 내가 생각한 대로 안움직이냐고.
'초보자/일반인'(라지만 결국 자기 자신)에게 익숙한 방식으로 동작되어야 마땅하지 않냐고.
꼭 저분만 그러는게 아니고 이런 식으로 성내는 사람들이 대대로 꽤 많았습니다.
가장 골치아픈게 어셈 코드 들고오는 부류죠.
이해시키는게 가장 어렵습니다. 나름 전문가인데다가 어셈 코드에 기반한 믿음이 있거든요.

디스어셈블을 하느니 차라리 자기가 쓰는 컴파일러의 온라인/오프라인 메뉴얼을 읽어보는게
훨씬 시간 대비 효과가 좋을 겁니다.
그밖에 Effective ...류의 책이라던가 TC++PL, C/C++ FAQ, 위키피디아 영문판 같이
좋은 책이나 문서들은 널리고 널렸죠.

요새는 스택 오버플로우에 거의 모든 주제에 대한 질문과 답변이 있으며,
답변 수준도 굉장히 높고 정확한 편입니다.
필요할때 구글에 검색만 해봐도 사실 거의 다 해결됩니다.

kukyakya의 이미지

+1

HDNua의 이미지

좋은 답변 잘 읽었습니다. 답글로 남겨서 기억해야겠어요.

저는 이렇게 생각했습니다.

kaeri17의 이미지

정말 추천을 드리고 싶은 게시물이네요. 사실 잘못된 이해를 바탕으로 스스로 주장하는게 왜 안되냐는 사람들을 제대로 된 길로 인도하기가 제일 어렵죠. 뭔가 논리적인 답변을 해 주자니 수준이 너무 올라가 질문자가 이해를 못할것 같고, 그렇다고 뭔가 받아들여라고 하면 반발하고... 굳이 컴퓨터분야 뿐만 아니라요...

dltkddyd의 이미지

고수는 아니신가 보군요. 그런 것 설명하기 힘들어서 못 하는 거겠죠. 그러니 님 고수가 아니라는 겁니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

맞는 말씀입니다만..
이 경우 애초에 저렇게 전달하면 아예 잘못된 객체 주소를 가리키죠. 잘 된다고 하셨는데 아마 추상적인 C++ 코드 수준에서만 이리 저리 실험해보다가 뭔가 착각하신거라 봅니다. 이런 때는 아예 바닥을 뜯어내서 보면 그게 왜 잘못되었는지 물리적인 수준에서 감각할 수 있습니다.
어차피 C++은 추상적 개념이 물리적 레이아웃을 감안해서 설계되었고, 상부든 하부든 어느 한쪽에 대해 제대로 파고 들다보면 다른 쪽에 대한 이해도 깊어지게 마련입니다. 문제는 제대로 파고 드는게 아니라 혼자 상상하면서 적당히 개념을 지어내니까 그런거죠.

dltkddyd의 이미지

배열이 아닌 객체 하나를 레퍼런스로 전달 할 때도 잘못된 객체 주소라 할 수 있나요? 부모포인터는 자식포인터를 받을 수 있죠. 문제는 배열방식의 접근 방법을 지적하시는 것으로 보이는데, 그게 잘못됐다면 왜 Child의 get()함수가 제대로 호출되어 그 Child의 length가 출력됩니까? 댁은 굉장히 무지해보이는군요. 익명으로 계속 닉네임 없이 글 올리는데. 댁은 닉부터 만드세요. 닉 없는 놈하고는 말하기 싫다니까. 잘 모르는 놈이 주제넘게 답변은 다냐? 달지마. 너 같은 놈한테 답변 받지 않아도 되니. 답변 달지마라.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

그러게요, 왜 제대로 호출될까요? 안그래도 이상하다 싶어서 직접 해보았습니다.

g++ a.cpp
a.cpp: In function ‘int main()’:
a.cpp:52:14: error: cannot convert ‘Child (*)[3]’ to ‘Parent*’ for argument ‘1’ to ‘void f(Parent*, unsigned int)’

형 변환 에러가 나네요. 올려주신게 컴파일 되는 코드 맞나요?

하여간 실행은 해보려고 강제로 형변환을 해보았습니다.

f(reinterpret_cast(&child2), 3);

get in Child
5
get in Child
7
세그멘테이션 오류

당연하겠죠

익명 사용자의 이미지

뭔가 오해하는거 같은데 이 쓰레드에만도 나말고 최소 두명은 익명으로 쓰고 있습니다.
바로 위에 사람은 나랑 다른 익명입니다.
익명이 한사람이 아니에요.

dltkddyd의 이미지

		cout< <pa[i].get()< <endl;//이 부분을 제대로 이해해야 함.  get() 함수가 가상함수인 것을 알고 동적타입의 단위로 pa가 가리키는 대상
		//체를 나눈다.  그리고 동적결합에 의해 Child의 get() 함수를 호출한다.  
		//이 설명이 맞나요?
                //cout< <pa[i].length< <endl;
                //위 주석 코드는 오류를 유발합니다.  그런데 get함수 앞에 언급한 pa[i]는 오류를 유발하지 않습니다.  
                   //그 이유가 궁금합니다.

이 주석부분은 지우고 올리려고 했던 글입니다. 바빠서 지우지 못했군요.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

익명 사용자의 이미지

예제코드 제대로 올린거 맞나요?
오타가 아니라면 f(&child2,3); 이 코드가 컴파일 되는 것 자체가 이상한 겁니다.
함수 f의 첫번째 매개변수의 타입은 Parent * 인데 &child2의 타입은 pointer to array[3] of Child 입니다. 서로 호환 안되요.

error: cannot convert 'Child (*)[3]' to 'Parent*' for argument '1' to 'void f(Parent*, unsigned int)'

컴파일중에 이거 비스므리한 에러 안뜨던가요?
똑같은 숫자 찍힌다고 똑같은 주소값이 아닙니다.
이게 어셈블러 개념으로 포인터 이해하는 사람들의 문제점이죠.

익명 사용자의 이미지

저게 왜 잘못되었는지, 왜 컴파일러가 저런 에러를 내는지는 저 Child 배열의 메모리 맵을 그려보면 이해할 수 있습니다.
문제는 이 분은 메모리 맵을 나름 그렸는데, 그게 틀렸죠! 어디가 틀렸는지는 실제 코드와 대조하면서 확인하면 됩니다.. 귀찮은 작업이죠. 이 분은 그 작업을 직접 해보는 대신, 게시판에다가 자기 상상을 과시하는 중이고요.. 컴파일도 안되는 코드로..

익명 사용자의 이미지

Child 배열의 내부 메모리 구조하고는 별개로,
그냥 서로간의 포인터 타입이 호환되지 않는 것만으로도 문제가 됩니다.

배열에 &연산자가 붙으면 그 배열 전체에 대한 포인터 주소값이 되고,
배열 전체에 대한 포인터는 배열의 한 원소에 대한 포인터랑 서로 호환되지 않습니다.
위 에러 메시지의 의미가 바로 그런 뜻입니다.

익명 사용자의 이미지

"&"child2 였군요. 님의 말씀이 맞습니다.

다만 이 분의 의도대로, f(child2, 3)으로 하면 컴파일 에러가 나지 않습니다. 그런데도 세그폴트는 나지요.

dltkddyd의 이미지

됐었는데요. 저 컴파일은 외부에서 접속해서 원격으로 컴파일 했었거든요. 그렇다면 원격 접속 프로그램에서 문서 변경시 제대로 저장돼지 않은 채로 컴파일을 했나 봅니다. 내일 다시 점검해봐야겠네요. 아래 답변 주신 글도 내일 다시 문서 점검해서 확인해봐야 겠습니다. 여러 모로 감사합니다.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

bacon의 이미지

>>> 이런 경우에는 vptr이 없는 건지 vptr은 있지만 값이 기본값으로 설정되 있는 건지 확신할 수 없지만 vptr이 없다면 그 없음을 또는 기본값이 설정돼 있음을 기준으로 정적결합임을 식별해서 Child의 단위로 해당 객체에 접근한 다음에 정적타입으로 데이터를 읽어서 Parent 범주의 get 함수에 접근하는 것인가요? 실행시 컴파일이 포인터의 정적타입, 동적타입 모두 사용할 수 있는 것인지 궁금합니다.

그래서 virtual이라는게 필요한거 아닙니까? 빼면 뭘 넘겨줘도 Parent::get()이 호출되겠죠. 컴파일러가 virtual인지 아닌지 보고 정적으로 호출하는 코드를 생성하는지, 동적으로 호출하는 코드를 생성하는지를 결정하는거죠. 어떻게 하면 이렇게 동적으로 호출이 가능하지 궁금하면, 위에 다른분이 써놓은 링크같은 문서를 보거나, 직접 컴파일러의 소스를 한번 보면 되겠죠.

>>> //cout< >>> //위 주석 코드는 오류를 유발합니다. 그런데 get함수 앞에 언급한 pa[i]는 오류를 유발하지 않습니다.
>>> //그 이유가 궁금합니다.

length가 Parent에 없으니까 그렇죠. 있어도 virtual같은걸 할수 없기때문에 Parent::length만 찍히겠지만요.

bacon의 이미지

다른분들이 대답 잘 하신것 같은데... f(child2, 3)로 가정하고, 윗분들이 이야기 한것을 다시 정리해 봅니다.

글쓴분은 배열로 전달되었으니까,

&pa[0] == &child2[0], &pa[1] == &child2[1], &pa[2] == &child2[2]라고 생각하시는것 같은데,

sizeof(Parent) == sizeof(Child)라는 조건이 만족하면 그렇게 될수 있지만, 위 코드에서는 sizeof(Parent) < sizeof(Child)이 될수 있기 때문에 이렇게 되지 않습니다. pa[0].get()은 실행되겠지만 pa[1].get()하고 pa[2].get()은 제대로 호출이 안되겠죠.

&pa[0]은 &child2[0]와 항상 같겠지만, &pa[1]은 (char*)&child2[1] - (sizeof(Child) - sizeof(Parent)) 되겠네요.

본인 머신에서 잘 된건 아마 sizeof(Parent) == sizeof(Child)가 만족된 상황이었을 거예요. Alignment나 Packing등의 이유로 말이죠. 확실히 안되게 하려면 Child에다가 char dummy[128]; 같은걸 멤버로 넣어서 sizeof(Child)가 alignment나 packing상관없이 sizeof(Parent)보다 커지게 만들어 보세요. 윗분들 처럼 프로그램이 죽을겁니다.

dltkddyd의 이미지

"&pa[0] == &child2[0], &pa[1] == &child2[1], &pa[2] == &child2[2]라고 생각하시는것 같은데,"라고 말씀하셨는데, 그렇지 않습니다. 그게 안 되야 되는데 되더라는 겁니다. 그러니까 제 생각도 님과 같습니다. 그런데 접근이 되니 그점이 이상해서 질문을 올렸던 것이고요. 어떤 분은 컴파일이 되냐고 말씀하시던데요. 됐었습니다. 지금 다시 컴파일을 해봐서 결과를 봐야 겠습니다. 원격 때문에 문서 저장에 이상이 있었던 것인지 살펴봐야겠습니다.
그리고 위에서 제가 언급했던 글 중에

		cout<<pa[i].get()<<endl;//이 부분을 제대로 이해해야 함.  get() 함수가 가상함수인 것을 알고 동적타입의 단위로 pa가 가리키는 대상
		//체를 나눈다.  그리고 동적결합에 의해 Child의 get() 함수를 호출한다.  
		//이 설명이 맞나요?
                //cout<<pa[i].length<<endl;
                //위 주석 코드는 오류를 유발합니다.  그런데 get함수 앞에 언급한 pa[i]는 오류를 유발하지 않습니다.  
                   //그 이유가 궁금합니다

이 부분을 보고 나름대로 상상하고 있다고 비판하셨던 것 같스빈다. 저 주석 설명은 지우고 올리려 했던 겁니다. 바쁘게 글을 올리다 보니 지우는 것을 잊고 올린 것이고요. 제 마음의 생각이었죠. 아마 이 글 때문에 포인터로 배열방식 접근하는 방법을 모른다고 생각하셨던 것 같네요. 그런 기본은 저도 압니다. 이상하게도 컴파일이 되고 child의 get 함수가 호출되기에 의아해서 질문을 드렸던 것이고요.

본인 맞습니다.
인증샷
우헤헤헤... 로 대신합니다.

bacon의 이미지

제가 될수도 있는 이유를 위에 써놓았죠? 되는 머신에서 sizeof(Child)하고 sizeof(Parent)를 출력해보세요. 이게 동일할겁니다. 일반적으로 Aligment크기가 sizeof(int) * 2보다 크거나 같으면 그렇게 되겠죠. 예를 들면, 64비트 아키텍쳐에 8byte Alignment이고 sizeof(int)가 4바이트면 그렇게 되겠죠.

안되게 하려면 내가 위에서 말했던것처럼 Child가 확실히 커지게 하거나, Alignment관련된 pragma나 attribute를 사용하여 Alignment를 조정해보거나, 32bit아키텍쳐로 컴파일 해보거나 (sizeof(int)==4에 4byte alignment가정)등등을 시도해보면 되겠네요.

bacon의 이미지

그리고 이런 코드였으면 사이즈 상관없이 잘되었겠죠.

void f(Parent** pa,unsigned int length) {
        for(unsigned int i=0;i<length;i++) {
                cout<< pa[i]->get()<< endl;
        }
}
 
int main () {
        Child child2[3]={Child(7), Child(9), Child(10)};
        Child* child3[3] = { &child2[0], &child2[1], &child2[2] };
        f((Parent**)child3,3);
}

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.