반응형

원인


"error C4996: 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details."
"error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details."

scanf와 같은 함수 사용 시 C4996 오류가 발생하는 원인과 이유 그리고 해결 방법에 대해서 알아보자.

 

최신 Visual Studio에서 C4996 오류가 발생하는 이유는 scanf, strcpy, fopen 과 같은 함수들을 사용했기 때문인데,

이 함수들은 버퍼 오퍼플로우(BOF) 등의 보안 취약점을 가지고 있으므로 사용을 자제하라는 의미이다.

 

이러한 위험성을 가진 함수들은 C++14 이상에서는 deprecated 되어 있다.

728x90

해결 방법


1. 안전한 함수로 대체 하기 scanf_s, strcpy_s, fopen_s (★Best)

가장 권장되는 방법은 보안 취약점이 해결되는 안전한 함수로 대체하여 사용하는 것이다.

scanf_s, strcpy_s, fopen_s 등의 secure 함수로 대체하여 사용하면 오류가 해결되며, 동시에 취약점도 해결할 수 있다.

scanf_s("%d", &n);

 

2. 매크로 추가 #define _CRT_SECURE_NO_WARNINGS

scanf_s, strcpy_s 등의 함수는 안전하지만 그만큼 쓰기가 번거로운 경우가 있다.

취약점에 민감할 필요가 없는 코드를 작성하는 경우 코드 최상단에 _CRT_SECURE_NO_WARNINGS 를 정의해주면

해당 소스 파일(c, cpp)에서 이전과 같이 안전하지 않은(unsafe) scanf, strcpy, fopen 등의 함수를 사용할 수 있다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

(※주의. '#define _CRT_SECURE_NO_WARNINGS'는 반드시 최상단('#include <studio.h>' 보다 위)에 정의해야 한다.

 

3. 프로젝트 속성에서 SDL 검사 옵션 해제하기

SDL(Security Development Lifecycle) 옵션을 해제해주면 모든 소스 파일에서 안전하지 않은 함수를 사용할 수 있다.

  • [프로젝트 속성] -> [C/C++] -> [SDL 검사]: 아니요(/sdl-) 선택

* SDL(Security Development Lifecycle)이란? 보안 개발 수명주기의 줄임말로서, 개발 프로세스의 모든 단계에서 보안 및 개인 정보 고려 사항을 도입하여 개발자가 매우 안전한 소프트웨어를 구축하고 보안 규정 준수 요구 사항을 해결하며 개발 비용을 줄일 수 있도록 마련된 지침이다.

(출처: Microsoft SDL)


최신 Visual Studio에서 C4996 오류가 발생하는 원인과 이유, 그리고 해결 방법 3가지에 대해서 살펴보았다.

 

가능하면 SDL을 사용해서 취약점이 발생하지 않는 안전한 코드를 작성하는 것을 권장한다.

하지만 학교 과제나 개인 토이 프로젝트를 진행하는 경우라면 해당 옵션을 끄고 사용하면,

조금이나마 더 빠른 개발이 가능할지도 모르겠다.

반응형
반응형

/LTCG 링크 오류 발생 원인


"LINK : /GL로 컴파일한 MSIL .netmodule 또는 모듈이 있습니다. /LTCG를 지정하여 링크를 다시 시작하십시오. /LTCG를 링크 명령줄에 추가하면 링커 성능이 향상됩니다."

주로 Release 모드 빌드 시 발생하는 경고 메시지이다.

컴파일러 속성에서 '전체 프로그램 최적화(/GL)' 옵션이 켜져 있을 때 '전체 프로그램 최적화 안 함' 옵션이 선택되어 있는 경우 발생한다.

 

무시해도 컴파일은 되지만 성능을 위해 해결하는 것이 좋다.

 

728x90

해결 방법


  • [프로젝트 속성] -> [구성 속성] -> [일반] -> [전체프로그램 최적화] : 링크 타임 코드 생성 사용 선택
반응형
반응형

C/C++의 빌드 모드


C/C++의 Debug 및 Release 빌드 모드의 의미와 차이, 각 모드별 장단점에 대해서 알아보고, 추가로 성능 측정을 통해 실제 환경에서 비교해보자.

 

보통 C++로 코드 작성 후 결과물을 실행 파일로 만들기 위해서는 빌드 작업을 해야만 한다.

 

이때 Visual Studio와 같은 IDE에서는 Debug 또는 Release 빌드 모드를 선택할 수 있다.

이는 사실 C/C++ 컴파일러의 최적화 옵션의 차이인데, Visual Studio에서는 편의를 위해 빌드 모드를 분리해놓은 것이다.

 

Visual Studio의 빌드 모드 선택 항목

현업에 종사하거나 숙련된 개발자는 당연히 이 차이를 알고 있겠지만,

주로 C/C++ 개발을 처음 접하는 분들, 특히 학생들은 Visual Studio 기본값인 'Debug'로 빌드해서 배포를 하는 경우가 종종 있다.

 

잘못된 빌드 모드로 배포할 경우 성능 저하가 발생하거나 프로그램 실행 불가 등의 문제로 상당히 고생할 수 있다.

그러므로 각 빌드별 특징을 잘 알고있어야 한다.

728x90

 

Debug vs Release 차이점


그럼 Debug 모드와 Release 모드 빌드는 어떤 차이점이 있을까?

 

일단 이름에서도 알 수 있듯,

Debug 모드는 디버깅에 적합한 빌드이며,

Release 모드는 배포를 적합한 빌드이다.

 

빌드 구성의 세부 속성에 따라 일부 차이가 있을 순 있겠지만,

대체로 두 빌드에 대한 차이점을 요약하면 다음과 같다.

Debug Release
  • 코드 최적화 하지 않음
  • 바이너리(실행 파일) 크기가 크다.
  • 코드 실행 속도가 느림
  • 메모리 사용량이 많음
  • 바이너리에 디버깅에 필요한 정보가 포함됨
  • 컴파일 속도 빠름
  • 코드 최적화 과정 수행
  • 바이너리 크기가 작다.
  • 코드 실행 속도 빠름
  • 메모리 사용량이 적음
  • 디버깅에 필요한 정보가 거의 포함되지 않음
  • 컴파일 속도 느림 (최적화 과정이 포함되므로)

물론 코드 실행 결과는 동일하다.

 

각각의 빌드 모드는 언제 사용해야할까?

 

Debug 빌드는 코드 실행 속도가 느리지만, 디버깅이 용이하고 컴파일 속도도 빠르므로

한창 개발이 진행중인 프로젝트에서 개발자가 디버깅을 할때 사용하는 것을 권장한다.

 

Release 빌드는 코드 실행 속도가 빠르고 배포하기도 용이하므로 (VC++ 재배포 패키지) 개발이 완료되고,

실제 사용자에게 전달할 때 사용하는 것을 권장한다.

 

그러나 Release 빌드에서도 Debug 빌드에서 확인되지 않은 문제점이 발견되므로

Release 빌드에서의 테스트도 필수라고 할 수 있다.

 

Debug vs Release 성능 비교


그럼 Debug 빌드와 Release 빌드에서 성능 차이는 얼마나 발생하는 것일까?

 

간단한 테스트를 통해 각 빌드의 코드 실행 속도와 메모리 사용량을 비교해보자.

다음 테스트 결과가 모든 케이스를 대표하지는 못하겠지만, 참고용으로 활용할 수는 있겠다.

 

테스트는 '소수 구하기'이다.

#include <iostream>
#include <vector>
#include <Windows.h>

bool isPrime(int x)
{
    if (x <= 1)
    {
        return false;
    }

    for (int i = 2; i < sqrt(x); ++i)
    {
        if (x % i == 0)
        {
            return false;
        }
    }

    return true;
}

int main()
{
    int n;
    std::vector<int> vec;
    LARGE_INTEGER st, ed, freq;

    std::cout << "소수 개수 : ";
    std::cin >> n;

    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&st); // 측정 시작

    for (int i = 0; vec.size() < n; ++i)
    {
        if (isPrime(i))
        {
            vec.push_back(i);
        }
    }

    QueryPerformanceCounter(&ed); // 측정 완료

    std::cout << "소요 시간 : " << (double)(ed.QuadPart - st.QuadPart) / ((double)freq.QuadPart);
    system("pause");

    return 0;
}

100,000개의 소수를 구하는 방식으로 Debug, Release 빌드 각각 테스트하여 비교해볼 것이다.

 

빌드 환경

  • Windows 10 19H2 x64
  • Visual Studio 2019
  • Debug x86(/MDd /Od), Release x86(/MD /GL /O2 /Oi)

 

1. 실행 파일 크기 비교

Debug와 Release 모드로 빌드한 실행파일의 크기 비교

  • Debug  - 71.5KB (73,216 바이트)
  • Release - 15.0KB (15,360 바이트)

=> 약 4.7배 차이

 

2. 실행 속도 비교 (100,000개, 3회 평균)

Debug와 Release 모드로 빌드에 따른 실행 속도 비교

  • Debug  - 3.02014초
  • Release - 0.24319초

=> 약 12.4배 차이

 

3. 메모리 사용량

Debug와 Release 모드로 빌드에 따른 메모리 사용량 비교

  • Debug  - 1,000KB
  • Release - 844KB

=> 약 15%(156KB) 차이

    (단, 실행 파일의 크기가 커질수록 오차가 발생할 것이다.)


Debug 빌드와 Release 빌드 모드의 의미와 차이, 각 모드별 장단점에 대해서 살펴보았다.

각 빌드의 성능 측정 결과, 실행 파일 크기는 4.7배, 실행 속도는 12.4배, 메모리 사용량은 15% 정도 차이가 발생했다.

 

실제로 성능을 측정하여 비교해본 건 처음인데,

이번 케이스에서는 예상보다도 많은 차이를 보이는 것 같다.

 

위 내용을 참고해서 Debug와 Release 빌드를 적절히 활용하길 바란다.

반응형

+ Recent posts