프로그래밍2020. 5. 31. 20:07

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

 

위 에러 메시지로 인터넷을 검색하면 dll과 dll을 사용하는 프로젝트간의 함수 호출 규칙(cdecl, stdcall)이 달라서 발생하고 동일하게 맞춰주면 해결된다고만 나오지만 근본적으로는 함수 호출할때와 호출 끝났을때의 콜 스택이 달라졌을때 발생한다.

 

호출 규칙이 같아도 해당 에러메시지가 발생하는 경우는 아래와 같이 라이브러리와 라이브러리를 사용하는 프로젝트의 헤더가 달라서 가상함수 테이블이 다르고 전달인자가 다른 함수를 호출하게 되는 경우가 있다.

 

* 라이브러리 프로젝트 TestLibClass.h

#pragma once
class TestLibClass
{
public:
	TestLibClass();
	virtual ~TestLibClass();
	virtual void aaa();
#ifdef BBB
	virtual void bbb();
#endif
	virtual void ccc();
	virtual void ddd(int a);
};

* 라이브러리 프로젝트 TestLibClass.cpp

#include "pch.h"
#include <iostream>
#include "TestLibClass.h"

TestLibClass::TestLibClass()
{
}

TestLibClass::~TestLibClass()
{
}

void TestLibClass::aaa()
{
	std::cout << "AAA" << std::endl;
}

#ifdef BBB
void TestLibClass::bbb()
{
	std::cout << "BBB : " << std::endl;
}
#endif

void TestLibClass::ccc()
{
	std::cout << "CCC" << std::endl;
}

void TestLibClass::ddd(int a)
{
	std::cout << "DDD" << a << std::endl;
}

 

* 라이브러리를 사용하는 프로젝트의 main.cpp

#define BBB
#include "../TestLib/TestLibClass.h"

int main(void)
{
	TestLibClass* pTest = new TestLibClass();
	pTest->ccc();
	delete pTest;
	return 0;
}

 

라이브러리에는 BBB 가 정의되거나 전처리기에 추가되지 않아서 bbb()가 제거된 상태로 빌드되고

라이브러리를 사용하는 프로젝트에서는 BBB를 정의한 다음 해더를 포함했기 때문에 bbb()가 있는걸로 인식되어 ccc()를 호출하면 ddd(int a)가 호출된다.

 

pTest->ccc(); 에 중단점을 걸고 가상함수 테이블을 보면 아래와 같이 bbb()는 없고 끝에 널포인터가 하나 더 있다.

해당 라인에서 디스어셈블리로 이동을 해서 esi 와 esp의 값을 보면 아래와 같은데

함수 호출 후에는 아래와 같이 값이 변하고

__RTC_CheckEsp (0E012EEh) 에서 esi, esp값을 체크할 때 실패해서 Run-Time Check Failure #0 에러가 뜨게 된다.

 

ps. ddd(int a)를 ddd()로 수정해서 전달인자가 같은 경우에는 __RTC_CheckEsp를 문제없이 통과하지만 ccc()가 아닌ddd()가 호출된다.

 

ps2. ddd(int a)가 아예 없거나 ccc()대신 ddd(int a)를 호출한 경우에는 널포인터를 참조하게 되어 아래 에러가 뜬다.

"예외 발생(0x00000000, Test1.exe): 0xC0000005: 0x00000000 위치를 실행하는 동안 액세스 위반이 발생했습니다.."

Posted by 버블껌
프로그래밍2015. 5. 25. 01:52

예전 회사에 다닐때 VBA를 사용했었는데 책도 없고 인터넷도 사용할 수 없고 VBA도 잘 모르는 상황에서

급하게 숫자를 문자열로 만드는 로직이 필요해서 구현했었고

그 후로 이직중에 면접 문제로 비슷한 문제가 나와서 화이트 보드에 C언어로 구현해 본적이 있었다.


그러다 작년쯤에 심심해서 다음과 같이 해당 로직 그대로 C++ 템플릿으로 작성해 보았다.



물론 sprintf 방식으로 만들수 있다는 것도 알고는 있지만 이 방식으로 얼마나 빠를지가 궁금 했었고 

나중에 sprintf 방식으로도 만들어서 속도를 비교 해보려고 했었다.


이제 float과 double도 작성해야지 하고 있던 참에 std::to_string(), std::to_wstring() 을 발견하였다.

MSVS2013 기준으로 정수형은 모두 sprintf 로 구현되어 있었고 float, double, long double 도 구현되어 있었다.


그런 이유로 바로 속도 테스트 시작!


ToString Test Result

std result = count : 100, Total seconds :      0.000645, Average seconds :    0.000006, range : -9 ~ 9

std result = count : 100, Total seconds :      0.003895, Average seconds :    0.000039, range : -99 ~ 99

std result = count : 100, Total seconds :      0.043744, Average seconds :    0.000437, range : -999 ~ 999

std result = count : 100, Total seconds :      0.507521, Average seconds :    0.005075, range : -9999 ~ 9999

std result = count : 100, Total seconds :      5.388189, Average seconds :    0.053882, range : -99999 ~ 99999

std result = count : 100, Total seconds :     58.495743, Average seconds :    0.584957, range : -999999 ~ 999999

std result = count : 100, Total seconds :    648.189087, Average seconds :    6.481891, range : -9999999 ~ 9999999

std result = count : 100, Total seconds :   7002.231934, Average seconds :   70.022316, range : -99999999 ~ 99999999

std result = count : 100, Total seconds :  68199.750000, Average seconds :  681.997498, range : -999999999 ~ 999999999


Gum result = count : 100, Total seconds :      0.000341, Average seconds :    0.000003, range : -9 ~ 9

Gum result = count : 100, Total seconds :      0.002807, Average seconds :    0.000028, range : -99 ~ 99

Gum result = count : 100, Total seconds :      0.037484, Average seconds :    0.000375, range : -999 ~ 999

Gum result = count : 100, Total seconds :      0.503361, Average seconds :    0.005034, range : -9999 ~ 9999

Gum result = count : 100, Total seconds :      6.752371, Average seconds :    0.067524, range : -99999 ~ 99999

Gum result = count : 100, Total seconds :     79.450287, Average seconds :    0.794503, range : -999999 ~ 999999

Gum result = count : 100, Total seconds :    906.220520, Average seconds :    9.062205, range : -9999999 ~ 9999999

Gum result = count : 100, Total seconds :  10006.326172, Average seconds :  100.063263, range : -99999999 ~ 99999999

Gum result = count : 100, Total seconds : 102759.484375, Average seconds : 1027.594849, range : -999999999 ~ 999999999

( 각 마지막 9자리의 경우는 테스트 중에 컴퓨터를 사용했기 때문에 정확하지 않을 수 있다. )



1~3자리의 숫자는 내가 구현한 쪽이 빠르지만 4자리가 넘어가면 std::to_string() 이 더 빠르다.

( 자리수 별로 돌린게 아닌 숫자 범위로 돌렸기 때문에 -9999~9999 에 -999~999가 포함되어있다. )

Posted by 버블껌
프로그래밍2014. 6. 1. 06:00

엔진을 수정할때마다 샘플 프로젝트 들이 x86, x64, Debug, Release에서 모두 잘 컴파일 되는지 확인하기 위해 VS의 일괄 빌드를 자주 사용하는데

새로 만든 샘플 프로젝트의 x64 디버그 모드에서만 다음과 같은 에러로 빌드가 되지 않았다.


error LNK2038: '_ITERATOR_DEBUG_LEVEL'에 대해 불일치가 검색되었습니다. '0' 값이 '2'(xxx.obj에 위치) 값과 일치하지 않습니다.

error LNK2038: 'RuntimeLibrary'에 대해 불일치가 검색되었습니다. 'MD_DynamicRelease' 값이 'MDd_DynamicDebug'(xxx.obj에 위치) 값과 일치하지 않습니다.



일단은 프로젝트 속성의 구성 관리자에서 릴리즈로 되어있었던게 1차 문제였고



구성 관리자에서 디버그로 바꿨어도 일괄빌드에서는 릴리즈 설정이 그대로 남아있던게 원인이었다.


ps. 물론 근본적인 원인은 디버그로 빌드된 라이브러리를 릴리즈로 설정된 프로젝트에서 사용하려고 한것

Posted by 버블껌
프로그래밍2014. 5. 22. 22:43

DX11 입문서를 보면서 환경설정을 하고 디바이스 초기화 하는 부분을 따라서 코딩했더니 아래와 같은 경고가 떴다.



빌드가 안되는 것은 아니지만 찝찝했기 때문에 이리저리 설정을 바꿔보기도 하고 인터넷도 찾아보고 하다가 DX SDK가 Windows SDK에 포함되었다는 글을 보게 되었다.

바로 프로젝트 설정의 포함, 참조, 라이브러리 디렉터리 들에서 DX SDK의 경로들을 제거 했다.


하지만 DX와 관련된 소스들에서 정의되지 않았다면서 빨간 줄들이 생기고 컴파일을 하면 나오는 에러

D3D.cpp(2): fatal error C1083: 포함 파일을 열 수 없습니다. 'D3DX11.h': No such file or directory


하드에서 D3DX11.h 파일을 검색했더니 DX SDK에는 있지만 Windows SDK에는 존재하지 않는다.



멘붕 상태에 빠져있다가

#include <D3DX11.h>

#include <D3D11.h>

로 고쳤더니 에러도 사라지고 잘 컴파일 된다.

Posted by 버블껌
프로그래밍2014. 5. 17. 02:21

학원 다닐때 수업하면서 만들었던 엔진을 C++11을 적극적으로 사용하고 DX도 DX11로 업그레이드 하려고 프로젝트를 생성하고

코드들을 복붙하고 조금씩 수정하면서 윈도우 창을 띄우는 부분까지만 만들고 실행!

CPU만 25% 먹으면서 윈도우가 뜨지 않는다. OTL



한참동안 모니터를 뚫어져라 쳐다보고 람다가 문제인가 하면서 이리저리 바꿔 보기도 하고 디버깅 하면서 CreateWindow 함수가 왜 HWND를 null로 돌려주나 생각하다가 발견 했다.

WNDCLASSEX 구조체의 lpszClassName과 CreateWindow 함수의 첫번째 전달인자를 다르게 써서 라는 아주 허무한 이유가 원인이었다. OTL

Posted by 버블껌
프로그래밍2013. 8. 8. 20:51




SampleXbox360.zip




학원에서 수업중에 만들었던 엔진에 XBox360 패드를 지원하게 하려고 만들어본 예제이다.

텍스쳐는 용량 문제로 포함하지 않았기 때문에 스카이 박스와 중앙의 박스는 텍스쳐가 없이 출력된다.

좌우 스틱과 D패드는 중앙의 박스를 움직이게 하고 X,A 버튼은 누르고 있는 시간에 따라서 좌우 진동모터를 0~1로 동작시키고 Y,B버튼은 좌우 진동모터를 멈추게 한다.

X,A 버튼을 누르지 않은 상태에서 좌우 트리거를 누른 세기에 따라 좌우 진동모터를 동작시킨다.


LB, RB, Back, Start, 스틱 클릭에는 아무 설정도 되어있지 않다.


2013-08-13일 업데이트

 - XBox360 패드 입출력 클레스를 샘플 프로젝트에서 엔진 프로젝트로 옮김

 - 연결되지 않은 XBox360 패드도 매 프레임마다 체크 하던 것에서 1초마다 체크하는 것으로 변경

Posted by 버블껌
프로그래밍2013. 2. 14. 23:22

KGCA 게임 아카데미 23기 졸업프로젝트

팀명 : Dream Catcher

게임명 : Assault Arms



GumUITool.zip

Gum3DUI사용설명서.docx


Posted by 버블껌
프로그래밍2012. 12. 30. 20:27


프로젝트 중에 내가 맡은 UI의 랜더 부분 때문에 게임의 프레임이 튀는 문제가 생겼다.

UI의 프레임에서 화면크기만한 텍스쳐에 모든 오브젝트를 미리 그려놓고 UI랜더는 그 텍스쳐 한장만 화면에 그리는 비교적 단순한 로직이고 UI랜더를 포함함 모든 오브젝트는 최상위 부모 클래스의 같은 함수로 랜더되기 때문에 UI랜더에서 문제가 생긴다면 UI프레임에서도 문제가 생겨야 하지만 UI프레임에서는 문제가 생기지 않아서 이 문제의 원인이 상상조차 안됐었는데 의외로 간단한 부분이 문제였다.


다른 오브젝트와 UI랜더의 유일한 차이점은 UI랜더에서만 노말맵을 사용하지 않는 다는 것인데 기본 노말맵은 셋팅되어있고 노말맵을 NULL로 셋팅하려고 하면 예외처리로 원래 텍스쳐를 그대로 들고 있기 때문에 의도치 않게 노말맵을 셰이더에 보내주면서 셰이더에는 노말맵 텍스쳐를 선언하지 않은게 원인이었다.


ps. 컴퓨터는 거짓말을 하지 않는다.

컴퓨터가 거짓말을 한다면 그건 사람이 시켰기 때문이다.

그게 나야~~ 둠빠 둠빠 두비두밥

Posted by 버블껌
프로그래밍2012. 12. 2. 17:42




wofstream을 이용해서 파일에 저장하다가 한글이 출력되지 않는 문제가 있어서 아래와 같이 로케일을 한글로 설정해 주었다.


std::wofstream fStream(_strFileName);

fStream.imbue(std::locale("kor"));


한글 출력은 잘 되는데 숫자를 출력할때 999를 넘어가면 1,000 이런식으로 콤마로 분리해줘서 다시 읽어오는 부분에서 정상적으로 읽어오지 못하는 문제가 생겼다.


std::wifstream fStream(_strFileName);

fStream.imbue(std::locale("kor"));


읽어오는 부분에서도 로케일을 한글로 설정해서 해결됐다.OTL


ps. 만약 숫자를 콤마로 구분해서 저장되는걸 막고 싶다면

std::wofstream fStream(_strFileName);

fStream.imbue(std::locale("kor", std::locale::ctype));

이렇게 하면 된다.

Posted by 버블껌
프로그래밍2010. 6. 3. 04:27


컴퓨터 비젼 과목에서 교재에 있는 캠가드(침입자감시프로그램)를 이용해 A4용지를 탐색하고 A4용지의 위치에 다른 그림을 덮어 씌우는 증강현실 과제를 하고 있다.

일단 우리조는 영상의 일정한 간격의 점에서 A4용지로 의심되는 흰색 점을 찾고 그 점을 중심으로 해서 바깥쪽으로 A4용지의 외곽선을 탐색해서 다른 그림을 표시하려고 했었지만 어디선가 무한루프에 빠져서 프로그램이 멈춰버리게 되었다.

그래서 지금까지 했던것을 죄다 버리고 교수님께서 잘 안되면 해보라던 방법으로 하게 되었다.
어라 너무 쉽게 되어 버리네?


테스트 하는데 생긴 문제는 벽지가 흰색이라 A4용지하고 벽지하고 구분을 못하고 그렇다고 불을 끄면 A4용지도 어두워 져서 흰색이 아니게 되어 버렸다.
그래서 A4용지 대신에 휴대폰 화면을 사용하게 되었다.


Posted by 버블껌
프로그래밍2010. 5. 23. 01:59
드디어 게임이 정상적으로 진행되는데까지 만들었다.

아직은 컴퓨터가 랜덤으로 놓지만 미니맥스던 알파베타던 인공지능을 적용 시키고 게임 내용을 저장했다가 나중에 활용하게까지 만들면 완성이다.
근데 시간이 너무 부족해 OTL
Posted by 버블껌
프로그래밍2010. 5. 4. 22:20
인공지능 수업에서 우리팀은 오델로를 만들기로 해서 발표자료를 준비하던중에 WZebra란 프로그램을 알게 되었다.
이미 있는 프로그램을 찾아보고 우리꺼는 이거와 비교해서 무엇이 더 좋습니다 라고 해야되는데 제브라에는 있을거 다있네 OTL

컴퓨터가 60수까지 계산해서 수를 두게 설정할수 있길래 그렇게 설정해 보았다.
지금 25시간째 계산이 아직 안끝나고 있다.

이거 이번학기 끝나기 전에 끝나기는 하려나?


ps. 결국 30시간만에 포기 ㄲㄲㄲㄲㄲㄲ
Posted by 버블껌
프로그래밍2009. 7. 19. 16:06

클래스를 제대로 써본적도 몇번 없고

STL과 템플릿은 거의 이름만 들어본 나한테는

조금 이른 책일수도 있었지만

 

C++에 대한 전체적인 개념정리는 잘 된것 같다.

 

인상적이었던 부분 

시간은 계속 흐릅니다. 우리는 안 죽었고요. 계속 배워가는 겁니다.

Posted by 버블껌
프로그래밍2007. 11. 21. 11:02
2004년12월 20일에 내 싸이 게시판에 썼던 내용...
//티스토리에서 탭이 자꾸 스페이스 4번으로 바껴서 첨부파일로도 올림(본문과 같은 내용)

알바하다가 에소스 세미나 숙제 할까 했더니...
비쥬얼 스튜디오가 없어서...
그냥 여기다.ㅋㅋ
============================ 1번째 ========================

/***********************************************************
4로 나누어서 떨어지는 해는 윤년입니다.예를 들면 2004년 2008년.
100으로 나누어서 떨어지는 해는 윤년이 아닙니다. 2100년 2200년.
400으로 나누어서 떨어지는 해는 윤년입니다.2000년 2400년.
***********************************************************/
// 윤년이 아니면 0을 리턴, 윤년일 경우 1을 리턴...

if( (gumy % 4) == 0 )        //gumy 는 연도...함수에서 넘겨 받을 값...
{                //4로 나누어 떨어지면 윤년...
    if( (gumy % 100) == 0 )     //100으로 나누어 떨어지면 윤년아님
    {
        if( ( gumy % 400) == 0)
        {        //100으로 나누어 떨어지고 400으로 나누어 떨어지면 윤년
            return 1;
        }
        else
        {        //100으로 나누어 떨어지고 400으로 안 나눠지면 윤년아님
            return 0;
        }
    }
    else
    {            //4로 나누어지고 100으로 안나눠지면 윤년
        return 1;
    }
}
else
{     // 4로 안나누어 떨어지면 윤년아님
    return 0;
}

/*
너무 복잡한가?
*/

============================ 2번째 ========================

/***********************************************************
4로 나누어서 떨어지는 해는 윤년입니다.예를 들면 2004년 2008년.
100으로 나누어서 떨어지는 해는 윤년이 아닙니다. 2100년 2200년.
400으로 나누어서 떨어지는 해는 윤년입니다.2000년 2400년.
***********************************************************/
// 윤년이 아니면 0을 리턴, 윤년일 경우 1을 리턴...

if( ( gumy % 4 ) == 0 )        //gumy 는 연도...함수에서 넘겨 받을 값...
{                //4로 나누어 떨어지면 윤년...
    if( ( (gumy % 100) == 0 ) != ( ( gumy % 400) == 0 ) )
    {            // 100으로 나누어 떨어지면서
                // 400으로 나누어 떨어지지 않으면 윤년 아님...
        return 0;
    }
    else            //100으로 나누어 떨어지지 않거나
    {            //4로 나누어지고, 400으로 나누어지면 윤년
        return 1;
    }
}
else         // 4로 나누어 떨어지지 않으면 윤년아님
{
    return 0;
}

/*
뭐... 좀 간단해지기는 했나...ㅡㅡ;;
*/


==========================================================

여기 까지는 예전에 만들었던 내용이고...

3번째 부터는 2006년09월19일에 만든 것...

============================ 3번째 ========================

/***********************************************************
4로 나누어서 떨어지는 해는 윤년입니다.예를 들면 2004년 2008년.
100으로 나누어서 떨어지는 해는 윤년이 아닙니다. 2100년 2200년.
400으로 나누어서 떨어지는 해는 윤년입니다.2000년 2400년.
***********************************************************/
// 윤년이 아니면 0을 리턴, 윤년일 경우 1을 리턴...

if( ( gumy % 100 ) == 0 )    //gumy 는 연도...함수에서 넘겨 받을 값
{                //100으로 나누어 떨어지면 윤년아님
    if( ( gumy % 400 ) == 0)    //400으로도 나누어 떨어지면 윤년
    {
        return 1;
    }
    else            // 100으로만 나누어 떨어지면 윤년아님
    {
        return 0;
    }
}
else                // 100으로 나누어 떨어지지 않은 경우
{
    if( ( gumy % 4 ) == 0 )    // 4로 나누어 떨어지면 윤년
    {
        return 1;
    }
    else        //4로 나누어 떨어지지 않으면 윤년아님
    {
        return 0;
    }
}

/*
    2번째보다 길기는 하지만 이해하기는 좀더 편해졌음...
*/

==========================================================


뭐...예전에도 찾기는 했었지만...

네이버 지식인에는 이프문 하나로 만든것도 있더군...


if( !( gumy % 4 ) && ( gumy % 100 ) || !( gumy % 400 ) )
{
    return 1;
}
else
{
    return 0;
}

==========================================================

이렇게까지 줄일수가 있다니!!!

하지만 위에것을 수정해서 한줄로도 줄일수도 있다.

==========================================================

( !( gumy % 4 ) && ( gumy % 100 ) || !( gumy % 400 ) ) ? return 1 : return 0 ;

==========================================================
Posted by 버블껌