C 프로그래밍 중 파일입출력에 대한 질문이 있습니다.

ygbabe의 이미지

안녕하세요 임베디드 프로그래밍 중 막히는 부분이 있어 혹시나 조언을 받을수 있을까 해서 글을 남김니다.
현재 저는 라즈베리파이 기반의 음향 신호 수신 및 처리에 대한 프로그래밍 작업을 하고 있는데요 중간에 몇초간의 데이터를 파일로 저장하고 이중 지정된 길이의 데이터를 짤라 신호처리 함수로 전달하는 과정에서 데이터가 정상적으로 전달이 안되는 문제점이 발생하고 있습니다.
(현재 코드 상에서는 fft_calculate_ready 함수가 저장된 전체 파일에서 일정길이 N 만큼 짤라 이를 다시 파일로 저장하고 신호처리 함수 auto_correlation 함수에서 이를 다시 읽어 들이는 과정에서 컴파일에는 문제가 없으나 실행 후 segmenation fault가 발생하고 있습니다.- 이는 코드 주석처리 후 segmen-fault 발생부분을 체크하여 fread부분 실행 시 발생함을 확인하였습니다.)
제가 c프로그래밍 경험이 별로 없다보니 문제해결에 시간이 많이 걸려 도움을 구하고자 합니다.

별도로 파일 입출력과 관련하여 fread 함수 사용시 포인터변수에 파일데이터를 저장하고 이를 다시 읽어 들이는 과정에서 데이터량이 많을 경우 이를 처리하는데 발생할수 있는 문제점이 있는지 문의드립니다.

#define ALSA_PCM_NEW_HW_PARAMS_API
 
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
 
#include <sndfile.h>
#include <malloc.h>
 
#include <math.h>
#include <time.h>
 
#include <wiringPi.h>
 
//# include <fftw3.h>
 
#include "/opt/vc/src/hello_pi/hello_fft/mailbox.h"
#include "/opt/vc/src/hello_pi/hello_fft/gpu_fft.h"
 
#define SIZE 1024 //FFT ?
 
#define sRate 44100
#define rSec 1
#define frame 16
#define LENGTH sRate*rSec //read size
#define channel 1
//#define Input_Leng 2048 //fft re.im send to fft.power by input_leng
#define Input_Leng 1024
#define Buff_size 1024
#define BUFF_SIZE 1024
#define waittime 3
#define sleepTime 20
#define stime1 0
#define stime2 2
 
float fft_calculate_ready(char *inputfile, char *outputfile, long int offset, int log2_N);
//int fft_calculate(float *inputfile, int log2_N, char *filename, struct GPU_FFT_COMPLEX *base, struct GPU_FFT *fft);
 
float Auto_correlation(char *inputfile, int log2_N);
//float Cross_correlation(float *input1, float *input2, int time_lag);
 
struct GPU_FFT_COMPLEX *base; // float re[],im[]
struct GPU_FFT *fft;
 
int log2_N = 10;
 
 
int main()
{
 
	int i,k,j,N,M;
	FILE *fp_write;
	//FILE *fp_read;
	long timeLoops;
	int status;
 
	int rc;
	int size;
	snd_pcm_t *handle;
	snd_pcm_hw_params_t *params;
	unsigned int sampleRate = sRate;
	unsigned int channels = channel;
	unsigned int sSec1, sSec2;
	//unsigned int Input_Leng;
	int recordSec = rSec;
	int dir;
	snd_pcm_uframes_t frames;
	float *buffer; // pcm data
	float *tBuffer;
	//float tBuffer[N];
 
	time_t tm_time;
	struct tm *st_time;
	char buff[Buff_size]; // file name temp buffer
	char strbuff[Buff_size]; //save data file name
	char str2buff[Buff_size]; //resave file name
	char spbuff[Buff_size]; //signal processing data file name
	float buf[Buff_size]; //temp buffer
	float *Auto_result;
	//double *Auto_result;
 
	N = 1<<log2_N;
 
	//Auto_result = (double *)malloc(sizeof(double)*N);
	//float tBuffer[N];
	Auto_result = (float *)malloc(sizeof(float)*N);
 
	/* Open PCM device for recording (capture). */
	rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
	if (rc < 0)
	{
		fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
		exit(1);
	}
 
	/* Allocate a hardware parameters object. */
	snd_pcm_hw_params_alloca(&params);
 
	/* Fill it in with default values. */
	snd_pcm_hw_params_any(handle, params);
 
	/* Interleaved mode */
	snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
 
	/* Signed 16-bit little-endian format */
	snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
 
	/* Two channels (stereo) */
	snd_pcm_hw_params_set_channels(handle, params, channels);
 
	/* 44100 bits/second sampling rate (CD quality) */
	//sampleRate = 44100;
	snd_pcm_hw_params_set_rate_near(handle, params, &sampleRate, &dir);
 
	/* Set period size to 32 frames. */
	frames = frame;
	snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
 
	/* Write the parameters to the driver */
	rc = snd_pcm_hw_params(handle, params);
	if (rc < 0)
	{
		 fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
		 exit(1);
	}
 
	/* Use a buffer large enough to hold one period */
	snd_pcm_hw_params_get_period_size(params, &frames, &dir);
	//size = frames * channel *2; // 2 bytes/sample, 2 channels // 4096
	size = frames * 4; // 2 bytes/sample, 2 channels // 4096
	buffer = (float *) malloc(size);
	if(buffer == NULL) printf("buffer malloc failed\n");
	tBuffer = (float *) malloc(sizeof(float)*N);
	if(tBuffer == NULL) printf("tBuffer malloc failed\n");
 
	//sampleRate 44100, 2byte per sample and 2 channels, 5 sec record. so 44100*2*2*5 = 882000 byte
	/* We want to loop for 5 seconds */
	snd_pcm_hw_params_get_period_time(params, &sampleRate, &dir);
	timeLoops = recordSec*1000000 /sampleRate;
 
	time(&tm_time);
	st_time = localtime(&tm_time);
	strftime(buff,Buff_size,"%Y-%m-%d %H:%M:%S",st_time);
	printf(buff);
	printf("\n");
	sprintf(strbuff,"TEST_%s.txt",buff);
	sprintf(str2buff,"ACC_%s.txt",buff);
	sprintf(spbuff,"SP_%s.txt",buff);
 
	printf("setup complete...and wait %d sec\n",waittime);
	sleep(waittime); // prevent beginning codec noise from sound data
	printf("ok..start recording %d sec...\n",rSec);
 
	int p_delay = 10;
 
	while (timeLoops > 0)
	{
		timeLoops--;
		rc = snd_pcm_readi(handle, buffer, frames);
		if (rc == -EPIPE)
		{
			/* EPIPE means overrun */
			fprintf(stderr, "overrun occurred\n");
			snd_pcm_prepare(handle);
		}
		else if (rc < 0)
		{
			fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
		}
		else if (rc != (int)frames)
		{
			fprintf(stderr, "short read, read %d frames\n", rc);
		}
			fp_write = fopen(strbuff,"ab");
			//fwrite( buffer,sizeof(float),rc,fp_write);
			fwrite(buffer,sizeof(float),frames,fp_write); //fwrite inner buffer 512 so... if frames 1024, no wait and send buffer to disk immediatedly
			fflush(fp_write);
	}
	printf("file save complete...\n");
	status = fclose(fp_write);
	if(status != 0)
	{
		printf("txt file save error!!\n");
		return -1;
	}
	free(buffer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
	//sleep(waittime);
	printf("time data file reading.....FFT process....\n");
 
	fft_calculate_ready(strbuff, str2buff, 0, log2_N);
 
	for(i=0;i<100000;i++);
 
	Auto_correlation(str2buff, log2_N);
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////
 
	snd_pcm_drain(handle);
	snd_pcm_close(handle);
 
	return 0;
}
 
float fft_calculate_ready(char *inputfile, char *outputfile, long int offset, int log2_N)
{
	FILE *input;
	FILE *out_file;
	int N,i;
	int p_delay = 10;
 
	N = 1<<log2_N; // FFT length
 
	printf("file reading...\n");
	//input = fopen(inputfile, "rb");
	input = fopen(inputfile, "rb");
	out_file = fopen(outputfile,"ab");
	if(input == NULL)
	{
		printf("ERROR: File %s not found.\n",inputfile);
		exit(1);
	}
 
	float *F_input, *F_out, *F_out2;
	//float F_input[N];
	int f_size;
	F_input = (float*)malloc(N*sizeof(float));
	F_out2 = (float*)malloc(N*sizeof(float));
	if(F_input == NULL) printf("F_input buffer failed\n");
	memset(F_input, 0, N);
	fseek(input,offset,SEEK_SET);
	while((f_size = fread(F_input,sizeof(float),N,input)) < N); fflush(input);
	if(f_size != N)
	{
		printf("file reading error..\n");
	}
 
	F_out = &F_input[0];
 
	for(i=0;i<N;i++)
	{
		F_out2[i] = *(F_out+i);
	}
 
	if((f_size = fwrite(F_out2, sizeof(float),f_size,out_file)) < 0)
	{
		printf("file %s write error\n",outputfile);
	}
	fflush(out_file);
	delay(p_delay);
 
	fclose(input);
	fclose(out_file);
	free(F_input);
	free(F_out2);
 
	//return 0;
}
 
//float Auto_correlation(float *input, int time_lag)
float Auto_correlation(char *inputfile, int log2_N)
{
	FILE *fp_auto;
	int i = 0;
	int N;
	N = 1<<log2_N;
 
	//float result = 0;
	float *inputdata;
	inputdata = (float *)malloc(sizeof(float)*N);
 
	float result = 0;
 
	fp_auto = fopen(inputfile,"rb");
	if(fp_auto = NULL) printf("file read failed\n");
 
	fread(inputdata, sizeof(float),N,fp_auto);
 
	//for(i=0;i<N;i++) printf("%f",inputdata[i]);
 
	//delay(10);
 
	fclose(fp_auto);
 
/*
	for(i = 0; i<Input_Leng - time_lag; i++)
		result = result + input[i] * input[i + time_lag];
 
	return result;
*/
	return 0;
}
ymir의 이미지

- if(fp_auto = NULL) printf("file read failed\n");
+ if(fp_auto == NULL) printf("file read failed\n");

core dump 떨어지면, 일단 gdb 로 먼저 확인해 보세요.

gdb 돌려봤다면, 그 밑에 있는 fread() 의 마지막 argument 에..
0x0 이 들어가는 걸 확인할 수 있었을 것 같네요.

추가로, 빌드할 때 -W -Wall 정도는 기본적으로 켜주시는게 도움이 많이 될 겁니다.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

ygbabe의 이미지

위에 부분과 함께 같이 막히는 부분이 fread 함수 사용 시 같이 사용되는 읽기데이터변수에 있는 데이터를 확인하고자 데이터 크기의 for문으로 printf 확인 시 전혀 다른 데이터가 표시되고 이 데이터변수를 fwrite를 써서 종료 시 파일 내 정상적인 데이터 쓰기를 확인할 수 있었습니다. 이러한 상황은 데이터변수의 함수로 전달과정에서 제한사항이나 프로세스에 대한 관련한 제가 모르는 부분이 있지 않나 싶은데요. 혹시 이런 부분은 알고 계신지 문의드리고 싶습니다.

...!의 이미지

뭘 물으시는 지 짐작은 갑니다만, 한참 생각하고 상상해서 알았습니다. 지금 프로그래밍을 공부할 때가 아니고 글 쓰기를 먼저 연습하셔야할 듯 합니다. 글은 둘째치고 먼저 문장을 어떻게 써야할 지를 고민해보시기 바랍니다. 맞춤법이나 띄어쓰기 이야기하는 것 아닙니다. 그런 것은 아무래도 좋습니다. 문제는 의사를 잘 전달할 수 있는 문장을 쓰는 겁니다. 기초적인 글쓰기 책을 하나 정해서 공부해보고 연습해보세요. 사람에게 지도를 받는 것이 훨씬 좋겠지만 일단 책으로라도 공부해보시기 바랍니다. 글을 잘 (최소한 무난하게) 쓸 수 없으면 프로그래밍은 무리입니다. 그냥 흉내나 좀 내보다가 노가다 프로그래밍으로 입에 풀칠이나 하겠지요. 그나마도 쉽게 안될 겁니다. 별난 천재가 아닌 이상 글쓰기 능력이 바로 생각하는 능력이고 프로그래밍 능력입니다. 그냥 가려다가 공부하시려는 의지가 있어보여서 몇 자 적었습니다. 흘려듣지 마세요. 인생이 바뀔 수 있습니다.

ygbabe의 이미지

제가 c프로그래밍을 독학으로 공부하는 과정에서 발생하는 이해하지 못한 문제를 설명하려다 보니 읽는 입장에서는 더 정리가 안되 보이는 듯 합니다. 그리고 말씀해주신 부분은 잘 듣고 실천하도록 하겠습니다.
다만 지금 발생한 문제는 해결하고 싶어서 조언을 구하고 싶습니다. size_t fread (void *data, size_t size, size_t count, FILE *stream) 함수에서 사용하는 data의 경우 중간에 임의의 버퍼를 거쳐서 임의의 데이터가 data변수 로 이동한다고 들었습니다. 이 과정에서 임의의 데이터가 data변수에 들어갔다는 확인이나 다른 방법이 있는지 문의드리고 싶습니다.

ymir의 이미지

buffered i/o 와 unbuffered i/o 의 차이에 대해 확인해 보시면 좋을 것 같네요.

그리고 함수에 대해 일일이 그 내용을 검증하고 사용하려 한다면..
굳이 라이브러리를 가져다 쓰는 이유가 없습니다.

fread 의 man page 를 보시면, fread 는 읽어들인 item 의 개수를 리턴한다고 되어 있습니다.
적어도 fread 가 내부에서 무슨짓을 해서 data 에 값을 저장하든지 간에..
fread 가 0 보다 큰 수를 리턴했다면, 적어도 data 에서 size * return 값 만큼에는..
정확하게 읽어들인 데이터가 들어 있다는게 보장될 거라는 뜻입니다.

즉, fread 가 파일에서 읽어서 data 에 저장하든..
일단 파일에서 한 번 버퍼에 읽어 들인 후, 그 버퍼에서 읽어서 data 에 저장하든..
어떤 방식을 사용하던지 간에.. 위에 있는 내용은 변하지 않습니다.

data 에 임의의 데이터가 들어간 것 같다는 얘기는..
fread 가 명세와 다르게 잘못 구현되어 있는 것 같다는 의미와 같아 보이는데..
한 번 쯤은 그렇게 생각해 볼 수도 있을 것 같습니다만, 높은 확률로 시간 낭비일 공산이 큽니다.

처음 공부하시는 상태라면, 우선은 함수를 정확히 이해하고 사용하는 데에 좀 더 집중하시길 권하고 싶네요.
함수를 사용하는 것과 그 구현 원리를 공부하는 것은 별개의 일입니다.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

ymir의 이미지

쉽고 뻔한 함수라도 한번쯤은 man page 를 꼼꼼하게 살펴보시면 도움이 될 겁니다.
가급적 정확하게 함수를 이해하고 사용하시라는 원론적인 이야기 밖에는 드릴게 없네요.

안전한 코드를 만드는 습관을 들이는 것도 필요할 것 같은데..
secure coding 으로 검색해 보시면 몇 가지 가이드를 얻을 수 있을 겁니다.

그보다 지금 같은 상황에서는..
이와 같은 문제에 직면했을 때 어떻게 대응할 것인가에 대한 부분이 좀 더 의미가 있겠네요.

segmentation fault (core dumped) 라는 메시지를 보고, segfault 가 뭔지, core 파일이 뭔지 검색해 봤다면..
접근해서는 안 되는 메모리를 침범했고, 그로 인해 프로그램이 죽으면서 메모리 덤프를 생성했고..
ulimit 명령으로 실제로 core 파일이 생성되게 할 수 있으며..
gdb 로 core 를 분석할 수 있다는 것 까지 바로 확인할 수 있었을 겁니다.
센스 있는 사람이면, 우선적으로 포인터를 의심해 볼 테구요.

빌드를 하거나 프로그램을 실행했을 때 화면에 나오는 모든 에러 메시지들은 나름대로의 의미를 가지고 있고..
현재 발생한 문제에 대한 힌트를 제공하고 있습니다.
그 힌트에 맞는 정확한 해결 방법을 찾아와야 한다는 거죠.

또 하나는, 도구에 좀 더 의존해도 좋다는 겁니다.
요즘 컴파일러는 문법에 대한 에러는 물론 잠재적인 오류 상황에 대한 경고도 띄워주는 자상함을 가지고 있습니다.
물론 완벽한 건 아니지만, 사람들이 흔히 하는 실수들에 대해서는 충분한 정도입니다.
더구나 런타임시에 메모리나 시스템 콜 호출 등을 분석할 수 있는 디버깅 툴들도 많습니다.
적어도 각 용도별로 하나씩은 손에 익혀두고 사용하시면 많은 경우에 있어서 시간을 절약할 수 있을겁니다.

최소한 gdb, valgrind, strace, ltrace, lsof 정도만 익혀 둬도..
대부분의 문제는 스스로 해결 할 수 있을 겁니다.

끝으로, 문제 해결을 위해 소스 코드만 올리는 것은 별로 도움이 되지 않습니다.
특히, 쉽게 빌드하기 어려운 코드라면 더더욱 도움이 안 됩니다.
단순히 눈으로만 긴 코드를 읽어서 오류를 찾아내는 거..
아무리 대단한 사람이라도 적지 않은 시간을 들이지 않고서는 어렵습니다.
더구나 사람은 습관의 동물이라 자기와 다른 패턴의 코드는 눈으로 봐도 오류를 인지하기가 쉽지 않습니다.

마침 라즈베리 갖고 놀던 중이라, 그냥 긁어서 빌드해 보니, 컴파일러가 경고 띄워주길래 답을 단건데..
경고도 없었다면, 제 라즈베리에서는 실행할 수 없는 프로그램이라 문제를 발견하지 못했을 겁니다.

반면 gdb 나 strace 의 내용을 올렸다면, 소스 없었어도 쉽게 문제를 발견할 수 있었을 겁니다.
어떤 문제에 직면해 도움이 필요한 경우에는, 내가 어떤 정보를 주어야 사람들이 나에게 답을 줄 수 있을지..
그 관점에서도 한 번 고민해 보시면 좋을 것 같습니다.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

ygbabe의 이미지

c프로그래밍을 독학으로 진행하다보니 아직 실용적인 부분이나 좀 더 전문적인 부분까지는 알지 못하고 그래서 답답한 마음에 조언을 구하고자 글을 올렸는데 제가 생각한 부분보다 더 많은 부분에서 부족함을 느끼고 갑니다. 긴 문장으로 자세히 설명해주셔서 감사합니다.

bushi의 이미지

fp_write = fopen(strbuff,"ab");
를 while loop 밖으로 빼고 "wb" 로 바꾸시고, 필요없는 fflush() 는 삭제하세요.

오디오(ADC) 장치가 무엇인지는 모르겠지만, float 형으로 PCM 데이타를 내놓지는 않을 것 같습니다.
도대체 뭐가 출력되어야 "printf 확인 시 전혀 다른 데이터가 표시" 되는 것이 아니게 되는지 설명할 수 있으신가요 ?

unsigned short x[2] = { 16384, 16384};
float *y = (float*)x;
printf("%f\n", *y)

댓글 달기

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