티스토리 뷰
scanf() 함수를 사용하기 불편하고
예외처리를 추가할때 자료형별로 함수를 하나하나 만들어 줘야할 생각을 하니까
하늘이 깜깜해져서
여기저기 알아보다가
C에 _Generic()이라는 기능과 <stdarg.h> 에서 variable arguments 기능을 제공한다는걸 알게되서
기능을 활용해서 scanf() 함수를 더 편리하게 만들어 볼려고 노력했습니다.
_Generic() 기능은 자료형을 매개인자로 받은뒤에 자료형에 따라 기능이 작동합니다.
switch() 문인데 자료형을 변수로 받는다고 생각하시면 됩니다.
<stdarg.h> 라이브러리는 표준 라이브러리로
함수의 매개변수 갯수나 타입에 상관없이 함수가 매개변수를 받을수있습니다.
함수 1개로 가변적 매개변수에 대응할수 있게 됩니다.
<stdarg.h> 는 C++의 Variadic Template의 기능과 비슷하다고 보시면 됩니다.
Input() 함수가 제공하는 기능
1. 숫자를 입력받을때 문자가 입력되면 0을 반환합니다.
2. 정수 문자열을 입력하다가 스페이스바로 공백을 중간을 준다면 0을 리턴합니다.
3. 함수를 사용할때 enum문에 나열된 값으로 자료형을 명시해줘야 합니다.
4. 변환된 값으 주소값을 리턴합니다.
5. 여러가지의 변수를 받을수있지만 1개만 적용되도록 했습니다.
6. 변수는 1개만 받지만 4가지 자료형에 대응 할수있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #include <stdarg.h> //va_list va_start va_arg var_end #include <stdio.h> //printf() scanf() NULL getchar() //C11부터 추가된 _Generic() 라는 옛날에 출시된 신기술 입니다. //비주얼 스튜디오에서 _Generic() 인식이 안되신다면 //컴파일러를 C11 지원이되는 컴파일러로 바꾸셔야합니다 //바꾸시는법은 제블로그에 설명되있습니다. //변수의 타입에 작동하는 switch문 이라고 보시면 됩니다. //모든 자료형을 구현해넣기보다 기본적인 서식자 4개만 판별하도록 하겠습니다. #define GET_FMT_SPEC(T) _Generic((T), int*: "%d%c", float*: "%f%c", char*: "%c", const char**: "%s%c") enum TYPE_NAME //자료 이름을 쉽게 가르키기위한 이넘문 입니다. { TYPE_INT, TYPE_FLOAT, TYPE_CHAR, TYPE_STR }; void* Input(enum TYPE_NAME _eType, ...); //입력값의 주소를 반환하고 입력타입과 변수의 주소를 넘기면 됩니다. int main() { //사용하기 int a = 0; Input(TYPE_INT, &a); float b = 0; Input(TYPE_FLOAT, &b); printf("%d, %f\n", a, b); return 0; //종료 } //TYPE_NAME 의 자료형과 매개변수의 자료형이 꼭 매치가 되야 합니다. void* Input(enum TYPE_NAME _eType, ...) { //제일먼저 인자들을 지역변수에 저장해둡니다. //지역변수에 따로저장해두면 코드수정에 용의해집니다. enum TYPE_NAME eType = _eType; va_list args; //... 에 입력될 변수들의 리스트 입니다. va_start(args, _eType); //첫번째 인자는 args 넣어주시고 두번째는 끝함수인자를 넣어주시면됩니다 void* pData = NULL; //변수의 주소값을 저장한후 나중에 반환할 변수 char cBuffer = 0; //정수를 입력받을때 문자가 섞여있는지 판단해줄 변수 switch (eType) { case TYPE_INT: //swtich문으로 자료형별로 대응합니다. { //va_args는 다음 인자를호출해주는 녀석 입니다. int* pInt = va_arg(args, int*); //scanf 는 입력이 잘된 갯수만큼 그정수를 리턴해줍니다 scanf(GET_FMT_SPEC(pInt), pInt, &cBuffer); *pInt = cBuffer == '\n' ? *pInt : 0; //버퍼에 개행문자가 입력됬다면 잘입력된겁니다. pData = pInt; //주소값을 저장한후 리턴합니다. } break; case TYPE_FLOAT: { float* pFloat = va_arg(args, float*); scanf(GET_FMT_SPEC(pFloat), pFloat, &cBuffer); *pFloat = cBuffer == '\n' ? *pFloat : 0.f; pData = pFloat; } break; case TYPE_CHAR: { char* pChar = va_arg(args, char*); scanf(GET_FMT_SPEC(pChar), pChar); pData = pChar; } break; case TYPE_STR: { const char** pStr = va_arg(args, const char**); scanf(GET_FMT_SPEC(pStr), *pStr, &cBuffer); *pStr = cBuffer == '\n' ? *pStr : "00000000"; pData = *pStr; } break; } //C++ Template 처럼 해보고싶었지만 시간이 많이 필요할것 같습니다. //함수포인터로 콜백 형식으로 만들어도 될것 같은데 //근본적으로 자료형으로 하나하나 일일이 만들어주기가 힘듭니다. //공용체를 만들어서 변수들을 넣어두고 //이넘문으로 변수형을 저장해둘까도 생각해봤는데. //그냥 C++ 로해야겠다... 라는 생각이 들었습니다. //타입을 확인해주는 기능이 필요합니다. //scanf 함수의 예외처리에 대응하기 위해서 scanf를 랩핑하는 형식으로 코드를 짜봤습니다. if(cBuffer != '\n') while (getchar() != '\n'); //cBuffer가 개행이아니면 뭔가 잘못됬다는거고 버퍼를 청소합니다. va_end(args); //스택을 정렬해줍니다. return pData; //편의를위해 보이드 포인터 주소값도 리턴해주겠습니다. } | cs |
'C > Console' 카테고리의 다른 글
N 진수를 입력받아서 N진수로 변환하기 (0) | 2018.11.14 |
---|---|
문자를 정수로 변환하는 함수를 만들어 봅시다 (0) | 2018.11.14 |
함수포인터를 이용한 계산기 (0) | 2018.11.12 |
유클리드 호제법 N개의 정수 최대공약수 구하기 (0) | 2018.11.12 |
1부터 N까지의 곱을 구하는 수 (0) | 2018.11.12 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- JS
- C11
- responsive slider
- CSS
- stdarg.h
- dropdown list
- slider
- SCSS @for
- .editorconfig
- 오류
- Generic()
- css slider
- C
- CSS 슬라이더
- Visual Studio 2017
- wxWidgets
- gettext
- HTML
- 1000 자리 계산기
- #C
- fyling fly
- C++
- scss slider
- _Generic()
- #비주얼스튜디오
- xgettext
- 도매인 가격비교
- scanf()
- 도메인 가격비교
- flying bee
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함