이미 아시는 분들도 굉장히 많으시겠지만 혹시나 도움이 될까하여 올립니다. 
아마 visual studio 2010에서는 c코드들이 잘 컴파일이 되고 실행이 되나, visual studio 2012, 2013, 2015에서는 scanf나 fopen등이 컴파일이 되지 않아 고생하시는 분들도 있을거라 생각됩니다.

일단 그 이유부터 말씀드리자면 개발자들이 함수의 오류가 발견되면, 그 함수를 deprecate해버리고 보안버젼의 새로운 함수를 추가해 버리기 때문입니다. 
(ISO에서 c++11 표준을 정하니 ms에서 visual studio 2012부터 바꾼거죠) 
예를들어 scanf의 경우 보안상의 문제로 c++ 98에서 c++11으로 넘어가는 과정에서 deprecated되버리고 scanf_s이라는 보안버젼 함수가 새로 생겨버렸습니다. 
visual studio 2010에서는 잘 컴파일이 되는데 visual studio 2012이상 버젼에서는 정상적으로 컴파일이 안되는 이유는 visual studio 2010에서는 default로 c++98을 사용하고, visual studio 2012이상 버전부터는 c++ 11을 사용하기 때문입니다. 

즉, visual studio 2012 이상 버젼부터는 scanf를 사용하면 warning이 뜨면서 컴파일이 안됩니다. 

scanf는 최근 몇년동안 보안 문제로 말이 있었죠. 뭐 이유를 알아보면 여러가지가 있지만 콘솔 io의 경우 input size를 정해주지 않으면 command를 같이 입력하는 방식으로 공격이 가능하다는데, 제가 보안쪽을 잘 몰라서 뭐라고 말을 더 못하겠군요. 뭐 이부분에 대해선 다른 블로거 님들에게 패스를 하고, 본론으로 다시 돌아가도록 하겠습니다.


이렇게 코드를 쓰고 컴파일을 하면 보통 에러가 나며 컴파일이 안됩니다.

#include <stdio.h>
int main()
{
	int inputNum;
	scanf("%d", &inputNum);
	printf("%d \n", inputNum);

	return 0;
}

이렇게 하고 start하면 아래 그림과 같은 메세지가 뜨면서 컴파일이 되지 않죠.


에러 내용을 해석해보면, scanf라는 함수가 안전하지 않으며, scanf대신 scanf_s라는 새로운 함수를 사용하는 것을 고려해 보라고 나옵니다. 또, deprecation된 함수를 사용하려면 _CRT_SECURE_NO_WARNINGS를 사용하라고 나오네요.(deprecation을 사용하지 않으려면)


그러면 지금부터 이러한 문제를 해결하는 방법을 몇가지 말씀 드리려고 합니다.

1. _CRT_SECURE_NO_WARNINGS를 사용하여 warning을 무시한다.


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	int inputNum;
	scanf("%d", &inputNum);
	printf("%d \n", inputNum);

	return 0;
}

이렇게 코드의 가장 윗부분에 _CRT_SECURE_NO_WARNINGS를 디파인 해주면 정상적으로 컴파일이 되는 것을 확인할 수 있습니다.

또는 에러 코드를 보면 C4996이라고 나오죠. 이 에러코드를 직접 무시하는 코드를 헤더 윗쪽에 추가 해서 정상적으로 컴파일을 하게 만드는 방법도 있습니다. 좀 자세히 말하자면 우리가 프로젝트를 만들때 SDL 체크를 사용하면 컴파일시 추가적으로 여러가지 보안 검사를 실시 하는데, 검사중에 경고 코드 C4996(사용되지 않는 함수 사용 경고)기능을 사용하지 않도록 설정하는 것입니다.


warning에 대한 링크 : warning-msdn

#pragma warning(disable: 4996)
#include <stdio.h>
int main()
{
	int inputNum;
	scanf("%d", &inputNum);
	printf("%d \n", inputNum);

	return 0;
}

이런식으로요 ㅎㅎ.

pragma에 대해선 나중에 #if, #ifdef등과 함께 나중에 한번 포스팅 하도록 하겠습니다.

2. 대세에따라 secure 버젼의 새로운 함수를 사용한다.

fopen의 경우 주소를 리턴하는게 보안상 문제가 있다고 판명되어 주소를 리턴하지 않고 인자로 받아 설정하는 fopen_s라는 secure버젼의 함수가 새로 만들어졌습니다.

사실 어떠한 함수가 deprecated가 되었다는 것은 sw전문가들이 문제가 있다고 생각되어 deprecated를 시키고 보다 안전한 함수를 새로 만들었다는 것이기 때문에 대세를 따라 secure버젼을 사용하는 것이 좋다고 개인적으로 생각합니다.


#include <stdio.h>

int main()
{
	FILE *data;
	fopen_s(&data, "test.txt", "w");
	fprintf(data, "%s", "Hello world!");
	fclose(data);

	return 0;
}

요런식으로 씁니다. ㅎㅎ


#include <stdio.h>

int main()
{
	char s[16];
	scanf_s("%s", &s, 16);//마지막에 input data size를 적어줍니다.(이게 scanf와 비교하여 바뀐부분이죠^^)
	printf(s);

	return 0;
}

scanf_s의 경우는 이런식으로 씁니다.

뭐 이러한 정보들은 구글링하면 바로바로 나오니 그때 그때 사용법을 검색해서 쓰기 쉽습니다.

유용한 사이트

CPlusPlus Page

MSDN Page

3. Project 생성시 SDL(Security Development Lifecycle) checks 옵션을 체크 해제한다.

이걸 체크해제하고 프로젝트를 만들면 추가적인 오류검사를 수행하지 않습니다. 예를 들어 함수의 반환형을 int로 해놓고 아무것도 반환하지 않아도 컴파일이 되고 실행이 됩니다. 뭐 컴파일이야 되겠지만은 별로 권장하고 싶진 않네요.


#include <stdio.h>

int main() {
	int inputNum;
	scanf("%d", &inputNum);
	printf("%d \n", inputNum);
}

위와 같은 코드도 컴파일이 됩니다.

어쨋든 SDL chechs 해제를 한번 해보죠.

1. 프로젝트를 만들어 줍니다.


2. 다음을 클릭합니다.


3. SDL checks의 체크를 해제해 줍니다.


4. 위의 코드를 한번 실행해 봅니다.

아주 잘 실행이 되는군요 ㅎㅎ



SDL에 대한 /sdl 링크 하나 남기겠습니다.

MSDN SDL

뭐 오늘 포스팅은 여기까지입니다. 마지막 방법은 되도록 쓰지 마세요 ㅎㅎ

'Programming > C/C++' 카테고리의 다른 글

Endian(Little endian, Big endian)  (0) 2015.10.08

+ Recent posts