[c++]cout의 객체반환에 대해서

again4you의 이미지

물어봐도 속 시원하게 답변해주는 사람이 없어서 염치 불구하고 여기에 올리게 되었습니다.

다음과 같은 간단한 코드에서 이상한 결과가 나오네요

#include <iostream.h>

int main()
{
	int update=6;
	int *p_update;
	p_update=&update;

	cout << "update is " << update << " and address update is " 
		 << &update << endl
		 << "*p_update is " << *p_update << " and address *p_update is "
		 << p_update << endl
		 << "++p_update is " << ++*p_update << endl; 
		 
	return 0;
}

결과
update is 7 and address update is 0x0012ff7c
*p_update is 7 and address *p_update is 0x0012ff7c
++*p_update is 7

여기서 제가 원하는 결과는 update = 6, *p_update = 6, ++*p_update = 7을 생각하고 있었는데 전혀 엉뚱한 결과가 나오네요

여기서

	cout << "update is " << update << " and address update is " 
		 << &update << endl
		 << "*p_update is " << *p_update << " and address *p_update is "
		 << p_update << endl;
	cout << "++p_update is " << ++*p_update << endl; 

위와같이 cout을 독립적으로 적으면 원하는 결과가 나오는 것를 확인했습니다.

그럼 cout 에서 반환되는 객체에 제가 모르는 부분이 있어서 어런 결과가 나오는거 같은데 찾아보고 물어보아도 다들 모른다고 하네요

설명을 부탁드립니다.
아니면 제가 공부해야 할 부분에 대해서 알려주시면 찾아 보도록 하겠습니다.

그럼 좋은 하루 보내세요
===============================================
독도는 우리땅!!

버려진의 이미지

뒤에서 부터 계산이 되는 겁니다. (위에것)
++*p_update가 가장 먼저입니다.
함수의 인수 전달 방식과 스택이 LIFO의 특성을 갖는 것 때문에 그렇습니다.

즉, 예를들어서

func(a,b,c);

이런게 있다면, push c, push b, push a 후에 func을 call합니다.

mangg의 이미지

func(a,b,c);

push c
push b
push a

call func

* 오른쪽에서 왼쪽으로 진행.

염두에 두소서..!^^

아는 부분이 나와서..위에서 언급한 부분...
등급좀 올리려고 몇자 적어봅니다^^

-------------------
나는 Copy&Paster 이다. 나의 화려한 기술 조합에 모두들 나를 두려워 한다. 나도 코드 Maker 이고 싶다.

douner의 이미지

함수에 인자를 전달하는 방식과는 상관이 없는 것 같습니다.
위의 설명대로라면...

cout << 'a' << 'b' << 'c';
출력 : cba

결과가 위처럼 되야할 것입니다.

질문된 코드를 다음과 같이 바꿀 수 있습니다.

cout.operator<<("update is ").operator<<(update).operator<<(" and address update is "). 
       operator<<( &update).operator<<(endl). 
       operator<<("*p_update is ").operator<<(*p_update).operator<<(" and address *p_update is ") 
       operator<<(p_update).operator<<(endl).
       operator<<("++p_update is ").operator<<(++*p_update).operator<<(endl); 

즉 cout 객체의 함수 operator<<() 에 인자 하나씩만 전달해서 호출합니다.
따라서 실행 순서는

cout.operator<<("update is ")(1)
.operator<<(update)(2)
.operator<<(" and address update is ")(3)
.operator<<( &update)(4)
.operator<<(endl)(5)
.operator<<("*p_update is ")(6)
.operator<<(*p_update)(7)
.operator<<(" and address *p_update is ")(8)
.operator<<(p_update)(9)
.operator<<(endl)(10)
.operator<<("++p_update is ")(11)
.operator<<(++*p_update)(12)
.operator<<(endl);(13) 

입니다. 그런데 출력이 왜 그렇게 나올까요... cout 은 바로 출력하지 않고 출력 버퍼에 값을 보냅니다.. 그래서 그런 것이 아닌가요? 출력 버퍼에서 변수는 변수의 주소를 가지고 있으므로 마지막에 (12) 번 호출에서 값이 바뀌면 그 값이 그대로 찍히는 것 같습니다.

인생, 쉬운 것만은 아니네..

버려진의 이미지

cout << 'a' << 'b' << 'c'; 는 이렇습니다.
먼저 c가 저장되고 b가 저장되고 a가 저장됩니다. 그리고 cout은 a를 먼저 꺼내고 b를 꺼내고 c를 꺼냅니다. 그래서 출력은 abc가 되죠.

cout<<a<<++a; 식이라면 이렇습니다. ++a가 저장되고 a가 저장되고 cout이 호출됩니다. a를 꺼내고(이미 증가되었죠) ++a를 꺼냅니다.

그래서 LIFO(FILO)인 것입니다.

douner의 이미지

Quote:
cout << 'a' << 'b' << 'c'; 는 이렇습니다.
먼저 c가 저장되고 b가 저장되고 a가 저장됩니다. 그리고 cout은 a를 먼저 꺼내고 b를 꺼내고 c를 꺼냅니다. 그래서 출력은 abc가 되죠.

(먼저 c가 저장된다는 의미를 << 'c' 멤버 함수가 먼저 호출되는 것으로 이해했습니다)
pyj200 님의 말을 따르면 C++ 언어의 멤버 함수 호출 순서가 뒤에서부터 왼쪽으로란 뜻이 됩니다. c 가 먼저 저장될려면 << 'c' 멤버 함수가 먼저 호출 되어 호출 스택에 먼저 Push 되어야 합니다.

#include <iostream.h> 

class Print
{
private:
	int num;
public:
	Print() : num(0) {}
	Print& Print1(void) { cout << num; return *this; }
	Print& Print2(void) { cout << ++num; return *this; }
	Print& Print3(void) { cout << ++num; return *this; }
};

위의 클래스를 예로 들면...

int main() 
{ 
   c.Print1().Print2().Print3();
   cout << flush;
   return 0; 
}

제가 이해한 것을 가정하에 pyj200 님의 말을 따르면 코드의 출력 결과는 122 이어야 합니다. 하지만 출력 결과는 012 입니다.

제가 잘 모르는 것일 수도 있으니 c 가 어떻게 먼저 저장이 되는지 자세히 알려주세요^^

인생, 쉬운 것만은 아니네..

버려진의 이미지

저는 문자 출력을 예로 들려고 했던 것이 아니라 처음 제기됐던 내용을 타이핑 하기 귀찮아서 약식으로 표기한겁니다. cout << 'a' << 'b' << 'c';를 컴파일 한다면 하나로 뭉쳐서 컴파일 되겠죠. 순서를 따질 여지도 없을 겁니다.

스택에 담기고 나오는 순서가 중요합니다.

c++에 대해서는 잘 모르지만 일단 문제제기하신 코드는
프린트1이 호출되고, 2가 호출되고, 3이 호출되지 않습니까? 그럼 1이 호출됐을때 0, 2가 호출되면 1, 3이 호출되면 2가 출력됩니다. 그러고 보니 이건 종류가 다른 예인데요... :/

...같은 내용의 글타래가 이전에 있었던것 같아서 검색해봤는데 못찾았습니다.

버려진의 이미지

http://khdp.org/docs/common_doc/shellcode만들기_0912.txt

좀 다른 분야이기는 하지만 이 문서를 한번 보시면 도움이 될것 같습니다.......

전 곡쓰러 가야 합니다. =3=3=3=3 내일부터 다작모드로 들어가기로 했거든요. 게임음악을 위해 =3=3

하루에 두곡씩 쓸 계획입니다.

douner의 이미지

아~ 이런이런... pyj200 님하고 하지 않아도 될 논쟁을 벌였습니다.
디버깅을 돌려보다가 정말 아차하는 순간에 이유를 알았습니다 ^^;;

이유는 전위++ 이냐 후위++ 이냐에 따라 그런 것이었습니다.

int a=0;
func(++a); // a 가 먼저 증가된 다음에 func 가 호출됩니다.
func(a++); // func 가 먼저 호출된다음에 a 가 증가합니다.

즉 그래서

cout << "update is " 
	    << update 
		<< " and address update is " 
        << &update 
		<< endl 
        << "*p_update is " 
		<< *p_update 
		<< " and address *p_update is " 
        << p_update << endl 
        << "++p_update is " << ++*p_update << endl;

은 함수 << 를 호출하기 전에 ++*p_update 문에 의해서 미리 7 로 증가되었던 것입니다..

VC++ 로 디버깅을 해보면서 처음에 전달되는 값은 "update is" 인데 그 다음 update 변수가 별안간 7 로 되어 있는 것이 아니겠습니까~ .. 왜 그럴까 하다가 저것이 바로 생각나더군요..^^;;

인생, 쉬운 것만은 아니네..

douner의 이미지

바로 글을 다셨네요..^^;
전 게임 프로그래밍에 관심만 많은 넘인데...-_-;;;
멋진 게임음악 만드시길 바랍니다.^^

인생, 쉬운 것만은 아니네..

akbar의 이미지

pyj200 wrote:

스택에 담기고 나오는 순서가 중요합니다.

스택에 담기고 나오는 순서가 중요하지만
C++ 사양은 인수의 평가순서과 마찬가지로
멤버 연산자를 중첩하는 경우
스택에 담기고 나오는 순서를 정의하지 않았습니다.
따라서

int p2=0;
cout<<(++p2)<<endl<<p2<<endl<<(++p2)<<endl<<(++p2)<endl;

라는 코드의 경우 출력값은
컴파일러에 따라서

3
3
3
3

이 될 수도 있고

1
1
2
3

이 될 수도 있습니다.

그러니
문의하신 경우처럼 코딩하는 것은 이식성이 없는 위헙한 코딩입니다.

again4you의 이미지

김형님, pyj200님, mangg님께 진심으로 감사드립니다.

특히 알려주신 내용 및 문서에 대해서는 더욱 공부해야 할 것 같습니다.

날씨 쌀쌀하신데 건강하시고, 좋은 하루 보내시기 바랍니다.

=============================================
독도는 우리땅!!

winner의 이미지

상당히 흥미로운 이야기여서 Assembly code 를 생성해봤습니다.
(언젠가는 저도 같은 실수를 했을지도 모르죠.)

모든 매개변수를 거꾸로 stack 에 쌓으면서 평가한 후 함수를 순서대로 호출하는군요.

C 에서 함수호출은 side effect 가 발생하지 않는 sequence point 에 해당합니다.
그냥 순서대로 호출하면 될 것을 왜 정의하지 않았는지...
또 GCC 는 어떤 연유로 매개변수를 몽땅 stack 에 쌓아 놓는지... -_-

혹시 어떤 이유가 있나요?
성능이 좋아질 것 같지도 않고...
stack 은 사용할대로 사용하고...

advanced의 이미지

Quote:

또 GCC 는 어떤 연유로 매개변수를 몽땅 stack 에 쌓아 놓는지... -_-

GCC 만 특별히 그러는것은 아니고요

C Calling Convention 이라고 하는 C에서 함수 호출시의 특성때문에

그렇습니다.

- advanced -

winner의 이미지

Advanced wrote:
GCC 만 특별히 그러는것은 아니고요

C Calling Convention 이라고 하는 C에서 함수 호출시의 특성때문에

그렇습니다.

C++ 에서 member 연산자 함수를 중첩하는 경우를 질문하는 것입니다.
각 member 연산자 함수는 독립적인 함수호출이잖아요.
중첩된 연산자 함수 호출이 마치 하나의 함수호출처럼 모든 매개변수를 쌓기에 이상하다는 것입니다.

또 한가지 질문이 전연연산자함수는 상관없나요?

akbar의 이미지

winner wrote:
상당히 흥미로운 이야기여서 Assembly code 를 생성해봤습니다.
(언젠가는 저도 같은 실수를 했을지도 모르죠.)

모든 매개변수를 거꾸로 stack 에 쌓으면서 평가한 후 함수를 순서대로 호출하는군요.

C 에서 함수호출은 side effect 가 발생하지 않는 sequence point 에 해당합니다.
그냥 순서대로 호출하면 될 것을 왜 정의하지 않았는지...
또 GCC 는 어떤 연유로 매개변수를 몽땅 stack 에 쌓아 놓는지... -_-

혹시 어떤 이유가 있나요?
성능이 좋아질 것 같지도 않고...
stack 은 사용할대로 사용하고...

인수가 필요한 멤버함수를 중첩해서 쓰는 경우
GCC 이건 어떤 컴파일러건 매개변수를 몽땅 stack 에 쌓아 놓습니다.

int i=10;
int j=20;
cout<<(5+(i*j+(30-j)*2)/3)<<endl;

위 코드의 경우 컴파일러가
(5+(i*j+(30-j)*2)/3) 을 계산하기 위해
각 수를 모두 스택에 넣어두고 계산합니다.(5,i,j,30,j,2,3)
같은 원리로 인수가 필요한 멤버함수를 중첩해서 쓰는 경우도
마찬가지이죠

처음 생각으로는 인수가 필요한 멤버함수를 중첩해서 쓸 때
그냥 순서대로 호출하면 될 것이 아니냐고 할 수도 있는데
위 코드 "cout<<(5+(i*j+(30-j)*2)/3)<<endl;" 과 같이
멤버함수를 중첩해서 썼더라도 C++ 에서 한 개의 명령을 구분하는
문자 ";" 을 만나기 전까지 나타나는 모든 인수를 스택에 저장해 놓고
한 번에 계산한다고 생각하시기 바랍니다.
그 이유는 "cout<<(5+(i*j+(30-j)*2)/3)<<endl;" 에서처럼
왜 C++ 은 각 수(앞에서 부터 5,i,j,30 등등) 를 스택에 먼저 저장하고
한 번에 계산하는지에 대한 답과 동일합니다.

주의하실 점은

int i=0;
cout<<(--i)<<i<<(++i)<<(++i)<<(i+100)<<endl;

의 경우
차례대로 (--i,i,++i,++i,i+100) 에 해당하는 수를 스택에 저장할 거라고 생각하지만
꼭 그렇지가 않은 것이
VC++ 의 경우 인수의 메모리 주소 공간이 같을 경우
두 번 저장하지 않습니다.

따라서 VC++ 에서는
(--i,i,++i,++i,i+100) 이 아니고
순서대로 --i, i, ++i, ++i 을 계산한 그 수 i 와 i+100 만 스택에 저장합니다.
즉 (최종 변수 i , i+100) 이렇게 2 개의 값만 스택에 저장하는 것입니다.

이전 글에서도 얘기했지만 이런 것은 어느 쪽이든
C++ 사양에서 정해지지 않은 것이므로
이식성이 없다는 점 주의하세요

전역연산자함수라고 해서 예외가 되지는 않습니다.

hyunuck의 이미지

읍.. 궁굼한게 하나 생겼는데요...
endl 이 flush 도 하지 않나요?
음.. flush 하는것과 스택에 들어가있는 함수를 처리하는 것과는 상관 없는가보군요...
갑자기 컴파일러에대해서 더 알아야겠다는 생각이 막....

하나 배우고 갑니다. 고맙습니다.

winner의 이미지

akbar 씨의 답변에 멤버함수라고 이야기하시는데 그렇다면 연산자함수만이 아니라 일반적인 멤버함수도 마찬가지라는 것인가요?
왜인지 일반 전역함수도 마찬가지라는 답변이 나올 것 같기에 더욱 의문입니다.

음... 제가 sequence point 에 대해 잘못 알고 있는 것 같네요.
제대로 공부안한 티가... (T.T)

akbar 씨의 글을 보면 언제나 C++ 의 새로운 가능성을 보는 것 같습니다.
솔직히 이해를 못하는 경우가 허다합니다만... -_-

hyunuck wrote:
endl 이 flush 도 하지 않나요?

맞습니다. 합니다. 그냥 '\n' 과는 다릅니다.
akbar의 이미지

winner wrote:
akbar 씨의 답변에 멤버함수라고 이야기하시는데 그렇다면 연산자함수만이 아니라 일반적인 멤버함수도 마찬가지라는 것인가요?
왜인지 일반 전역함수도 마찬가지라는 답변이 나올 것 같기에 더욱 의문입니다.

일반 전역함수도 마찬가지로 작동하며 같은 이식성 문제가 있습니다.
단 일반 전역함수를 멤버함수 중첩하듯이 쓸 수 있을 까요
물론 있죠

C++ 문자열 클래스 string 의 + 연산자가
대개는 전역함수로 선언되어 있습니다.

그래서 아래 코드가 가능합니다.

string cs("Love");
cout<<cs<<(cs="I " + cs + " C++" + " World")<<endl;

cout 는 cs 를 출력하고
다음에 (cs="I " + cs + " C++" + " World") 의 연산결과를
출력하고 있는 듯이 보입니다.

사용자는
처음 cout 이 cs 를 출력할 때 "Love" 를 출력하고
다음에 (cs="I " + cs + " C++" + " World") 의 연산결과를 출력할 때
"I Love C++ World" 가 출력되기를 바라겠지만
꼭 그렇지는 않고

"I Love C++ World" 이 두 번 출력될 수도 있습니다.
왜? 컴파일러에 따라서
최종적으로 인수 cs 가 가리키는 메모리 공간에서 값을 가져오기 때문에
"I Love C++ World" 을 두 번 출력하는 경우가 있게 되는 것이죠.

결국 이식성이 없어요 ...

douner의 이미지

와.. 정말 많은 것을 배우고 갑니다.
전 기본을 다시 딱아야 되겠네요^^

인생, 쉬운 것만은 아니네..

corba의 이미지

궁금해서 각 컴파일러 별로 테스트를 해봤습니다.

Visual C++ 6.0 SP5

update is 7 and address update is 0012FF7C
*p_update is 7 and address *p_update is 0012FF7C
++p_update is 7

Visual C++ 7.1

update is 7 and address update is 0012FEE4
*p_update is 7 and address *p_update is 0012FEE4
++p_update is 7

Borland C++ 5.6.4

update is 7 and address update is 1245064
*p_update is 7 and address *p_update is 1245064
++p_update is 7

Borland C++ 6.0 Preview

update is 6 and address update is 12ff24
*p_update is 6 and address *p_update is 12ff24
++p_update is 7

GCC 3.2

update is 7 and address update is 0x22ff6c
*p_update is 7 and address *p_update is 0x22ff6c
++p_update is 7

재밌는 건 Borland C++ 6.0 Privew만 결과가 다르게 나왔다는 사실입니다.
Borland측 말에 따르면 6.0은 표준 100%를 지킨다고 하더군요.
믿을 순 없겠지만...

ukira의 이미지

Quote:

스택에 담기고 나오는 순서가 중요하지만
C++ 사양은 인수의 평가순서과 마찬가지로
멤버 연산자를 중첩하는 경우
스택에 담기고 나오는 순서를 정의하지 않았습니다.

요게 무슨 뜻인지 몰라서 vc++ 7.1.3091 과 gcc 3.3.2 에서
테스트 해 봤는데요..

테스트 코드는 이렇구요..

int i=0;
cout << (i=i+1) << (i=i+2) << (i=i+3) ;

결과 값이...

Quote:

VC++ 7.1
666

gcc 3.32
136


으로 나옵니다.
디스 어셈블 해보니...

vc++은 계산을 다 해서 i 값을 만들어 놓고...
(그 과정에서 i=6이 됩니다.)
<< operator를 세번 호출합니다.

	cout << (i=i+1) <<  (i=i+2) <<  (i=i+3) <<endl;
0041BD65  mov         eax,dword ptr [i] 
0041BD68  add         eax,3 
0041BD6B  mov         dword ptr [i],eax 
0041BD6E  mov         ecx,dword ptr [i] 
0041BD71  add         ecx,2 
0041BD74  mov         dword ptr [i],ecx 
0041BD77  mov         edx,dword ptr [i] 
0041BD7A  add         edx,1 
0041BD7D  mov         dword ptr [i],edx 
0041BD80  push        offset std::endl (41A0B3h) 
0041BD85  mov         eax,dword ptr [i] 
0041BD88  push        eax  
0041BD89  mov         ecx,dword ptr [i] 
0041BD8C  push        ecx  
0041BD8D  mov         edx,dword ptr [i] 
0041BD90  push        edx  
0041BD91  mov         ecx,offset std::cout (457668h) 
0041BD96  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (4195D2h) 
0041BD9B  mov         ecx,eax 
0041BD9D  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (4195D2h) 
0041BDA2  mov         ecx,eax 
0041BDA4  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (4195D2h) 
0041BDA9  mov         ecx,eax 
0041BDAB  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (41A0B8h) 

gcc 3.3.2에서는 왼쪽부터 순서대로 << operator를 실행하네요...

0x08048624 <main+16>:   movl   $0x0,0xfffffffc(%ebp)
0x0804862b <main+23>:   lea    0xfffffffc(%ebp),%eax
0x0804862e <main+26>:   incl   (%eax)
0x08048630 <main+28>:   mov    0xfffffffc(%ebp),%eax
0x08048633 <main+31>:   mov    %eax,0x4(%esp,1)
0x08048637 <main+35>:   movl   $0x80499e8,(%esp,1)
0x0804863e <main+42>:   call   0x8048524
0x08048643 <main+47>:   mov    %eax,%edx
0x08048645 <main+49>:   lea    0xfffffffc(%ebp),%eax
0x08048648 <main+52>:   addl   $0x2,(%eax)
0x0804864b <main+55>:   mov    0xfffffffc(%ebp),%eax
0x0804864e <main+58>:   mov    %eax,0x4(%esp,1)
0x08048652 <main+62>:   mov    %edx,(%esp,1)
0x08048655 <main+65>:   call   0x8048524
0x0804865a <main+70>:   mov    %eax,%edx
0x0804865c <main+72>:   lea    0xfffffffc(%ebp),%eax
0x0804865f <main+75>:   addl   $0x3,(%eax)
0x08048662 <main+78>:   mov    0xfffffffc(%ebp),%eax
0x08048665 <main+81>:   mov    %eax,0x4(%esp,1)
0x08048669 <main+85>:   mov    %edx,(%esp,1)
0x0804866c <main+88>:   call   0x8048524

이걸 보고 생각한건데...
멤버연산자가 중첩된경우 호출 순서를 명시하지 않았다는 말이 이것처럼...
호출 순서가 순차적일수도 있고, 한번에 몰아서(-_-)할 수도 있다는 뜻인것 같습니다.

pynoos의 이미지

함수 argument를 항상 stack에만 쌓는 것은 아닙니다.

참고로 Sparc 같은 구조에서는 argument 몇개 까지는 register로 넘깁니다.

intel 계열에서도 fastcall 방식으로는 argument 두개까지인가는 register로 넘기도록 되어 있습니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.