프로그래밍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 버블껌
프로그래밍2009. 7. 19. 16:06

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

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

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

 

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

 

인상적이었던 부분 

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

Posted by 버블껌