반응형

 

#include<stdio.h>

int main(int argc, char *argv[])
{
	int number;
	scanf("%d", &number);
	printf("Number: %d",number);
	
	return 0;
}

위 코드는 문법적으로 문제가 없지만, 실행하면 VS에서는 에러를 출력한다.

 

그림1. C4996 에러

이는 scanf의 취약점(버퍼 오버플로우)때문에

VC 컴파일러가 scanf_s를 대신 사용하라고 경고하는 메시지이다.

이를 해결하기 위해서는 다음 방법들이 있다.


1. scanf_s 대신 사용하기.

#include<stdio.h>

int main(int argc, char *argv[])
{
	int number;
	scanf_s("%d", &number); // 기존 scanf와 다를것 없음.
	printf("Number: %d",number);
	
	return 0;
}

정수나 실수를 입력받을 때는 그냥 scanf와 다를 바 없이 사용하면 된다.

하지만 문자나 문자열을 입력받을 때는 인자가 하나 늘어난다.

#include<stdio.h>

int main(int argc, char *argv[])
{
	char ch;
	char string[10];
	scanf_s("%s", string, sizeof(string));
	scanf_s(" %c", &ch, 1);
	printf("String: %s\n",string);
	printf("Char: %c\n", ch);
	
	return 0;
}

변수 뒤에 입력받을 공간의 크기를 추가로 제공해주어야 한다.


2. #define _CRT_SECURE_NO_WARNINGS

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int main(int argc, char* argv[])
{
	int number;
	scanf("%d", &number);
	printf("Number: %d", number);

	return 0;
}

프로그램 맨 윗줄에 #define _CRT_SECURE_NO_WARNINGS라는 매크로를 추가하면 간단하게 해결된다.


3. #pragma warning(disable:4996)

#pragma warning(disable:4996)
#include<stdio.h>

int main(int argc, char* argv[])
{
	int number;
	scanf("%d", &number);
	printf("Number: %d", number);

	return 0;
}

또는 4996 경고를 무시하게 하는 전처리 명령을 추가하면 된다.


여담.

scanf_s는 Visual Studio에만 존재한다고 한다. (비표준)

따라서 Windows 환경에서만 C개발을 할 것이 아니라면 2번이나 3번 방법을 사용하는 게 낫다고 생각한다.


읽을거리.

scanf_s 함수 정의 및 예제

pragma warning의 사용법

버퍼오버플로우의 위험성 (스타크래프트 1 - EUD)

반응형

'개념정리 > C' 카테고리의 다른 글

Scanf 함수 공백처리  (0) 2021.04.12
반응형

 

#include<stdio.h>

int main(int argc, char *argv[])
{
	int ID;
	char name[10];
	char grade;

	printf("이름: ");
	scanf("%s", name);
	printf("학점: ");
	scanf("%c", &grade);
	printf("학번: ");
	scanf("%d", &ID);

	printf("%s(%d)의 학점: %c", name, ID, grade);

	return 0;
}

위 코드를 실행하면 두 번째 호출되는 scanf가 무시되고 넘어간다.

이는 첫번째 입력 이후 버퍼에 \n이 남아있어 %c입력에서 \n이 들어가서 발생하는 문제이다.

그림1. grade변수에 \n이 들어간 모습

이를 해결할 수 있는 방법에는 두 가지 방법이 존재한다.


1. 의미없는 입력 추가

#include<stdio.h>

int main(int argc, char *argv[])
{
	int ID;
	char name[10];
	char grade;

	printf("이름: ");
	scanf("%s", name);
	while (getchar() != '\n'); // 여기서 개행문자가 없어진다.
	printf("학점: ");
	scanf("%c", &grade);
	printf("학번: ");
	scanf("%d", &ID);

	printf("%s(%d)의 학점: %c", name, ID, grade);

	return 0;
}

코드를 보면, getchar함수를 호출하여 버퍼에 남아있는 개행 문자를 입력받는 것을 확인할 수 있다.


2. scanf의 수정

#include<stdio.h>

int main(int argc, char *argv[])
{
	int ID;
	char name[10];
	char grade;

	printf("이름: ");
	scanf("%s", name);
	printf("학점: ");
	scanf(" %c", &grade); // 서식지정자 앞에 공백추가
	printf("학번: ");
	scanf("%d", &ID);

	printf("%s(%d)의 학점: %c", name, ID, grade);

	return 0;
}

두 번째 입력을 받는 scanf앞에 공백 한 칸을 추가해주면,

앞서 존재했던 모든 공백 문자를 무시하고 새로 입력을 받는다.


그 외(fflush함수를 호출해 입력 버퍼를 비우는 방법)

이 방법은 C표준이 아니다!
fflush함수는 출력 함수를 비우기 위해 설계된 함수이다.
#include<stdio.h>

int main(int argc, char *argv[])
{
	int ID;
	char name[10];
	char grade;

	printf("이름: ");
	scanf("%s", name);
	printf("학점: ");
	fflush(stdin); // 동작안함.
	scanf("%c", &grade);
	printf("학번: ");
	scanf("%d", &ID);

	printf("%s(%d)의 학점: %c", name, ID, grade);

	return 0;
}

Visual Studio 2013 이하의 버전에서만 fflush함수로 표준 입력 버퍼를 비울 수 있다고 한다.

따라서 위 코드는 항상 동작하지는 않는다.

반응형

'개념정리 > C' 카테고리의 다른 글

Visual Studio C4996 에러 처리  (0) 2021.04.13

+ Recent posts