성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>어떤 것을 쓰면 좋을까요? ^^ wvnsprintf, _vsnwprintf_s, StringCbVPrintfW</h1> <p> 물론 상황에 따라 다르겠지요. ^^<br /> <br /> 일단 wvnsprintf를 사용하는 예제 먼저 볼까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > void OutputText(const wchar_t *format, ...) { wchar_t <span style='color: blue; font-weight: bold'>buffer[10]</span>; va_list vaList; va_start(vaList, format); int retval = <span style='color: blue; font-weight: bold'>wvnsprintf(buffer, 10, format, vaList);</span> // retval == -1 va_end(vaList); printf("%S\n", buffer); } int _tmain(int argc, _TCHAR* argv[]) { OutputText1(L"%d12345678901234567890", 0); // 출력결과: 012345678 return 0; } </pre> <br /> 위의 경우 OutputText 함수 내에 10개의 버퍼(wchar_t이므로 20바이트)를 마련했지만 인자로 들어온 값들이 이를 넘어서는 경우 반환값이 -1로 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > wvnsprintf function ; <a target='tab' href='https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-wvnsprintfa'>https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-wvnsprintfa</a> </pre> <br /> 하지만 문서에는 이에 대한 사용을 하지 말라고 나옵니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> <span style='color: blue; font-weight: bold'>Do not use this function.</span> See Remarks for alternative functions. <br /> <br /> Security Warning: Using this function incorrectly can compromise the security of your application. <span style='color: blue; font-weight: bold'>The copied string is not guaranteed to be null-terminated.</span> Consider using one of the following alternatives. StringCbPrintf, StringCbPrintfEx, StringCbVPrintf, StringCbVPrintfEx, StringCchPrintf, StringCchPrintfEx, StringCchVPrintf, or StringCchVPrintfEx. You should review Security Considerations: Microsoft Windows Shell before continuing. </div><br /> <br /> 근데 테스트해 보면 버퍼가 적어도 마지막을 '\0' 널 문자로 채워주었습니다. 아마도 예전 버전에서 그랬던 것인지, 아니면 특정 상황에서 그럴 수 있는지는 알 수 없으나 어쨌든 경고 문구가 있으니 달갑지는 않습니다. ^^<br /> <br /> 여기서 결론을 내면 좀 아쉽지만 결국 답은 StringCbVPrintfW를 사용하는 것이 좋습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #include <Strsafe.h> void OutputText3(const wchar_t *format, ...) { wchar_t buffer[10]; va_list vaList; va_start(vaList, format); int retval = <span style='color: blue; font-weight: bold'>StringCbVPrintfW</span>(buffer, <span style='color: blue; font-weight: bold'>sizeof(wchar_t) * 10</span>, format, vaList); // retval == -2147024774 va_end(vaList); printf("%S", buffer); } OutputText3(L"%d12345678901234567890", 0); </pre> <br /> StringCbVPrintfW가 wvnsprintf와 다른 점이 있다면 버퍼가 모자른 경우 반환값이 -1이 아니라 0x8007007A(-2147024774: The data area passed to a system call is too small.)로 나오는 점입니다.<br /> <br /> 그리고 버퍼 카운트가 wchar_t라고 해서 그 배열의 수를 그대로 전달하면 안되고 순수하게 byte 수를 전달해야 한다는 점입니다. 따라서 wvnsprintf는 버퍼 수를 10으로 줘도 되었지만 StringCbVPrintfW는 10 * sizeof(wchar_t)로 해야 합니다.<br /> <br /> 이제, 마지막으로 _vsnwprintf_s가 있는데... 이건 사용시 주의를 요합니다. wvnsprintf와는 달리 string safe 버전이기 때문에 대상 버퍼에 대한 관리가 특별합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > wchar_t buffer[10]; va_list vaList; va_start(vaList, format); int retval = <span style='color: blue; font-weight: bold'>_vsnwprintf_s</span>(buffer, 10, format, vaList); va_end(vaList); </pre> <br /> 단순히 사용하게 되면 버퍼가 모자르는 상황에 대해 디버그 빌드일 때는 예외 발생, 릴리스 빌드일 때는 프로그램 비정상 종료로 이어집니다.<br /> <br /> <img alt='output_format_text_1.png' src='/SysWebRes/bbs/output_format_text_1.png' /> <br /><br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Debug Assertioin failed! Program: ... File: f:\dd\vctools\crt\crtw32\stdio\vswprint.c Line: 358 Expression: ("Buffer too small", 0) For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts. (Press Retry to debug the applicaiton) </pre> <br /> 그래서 아무 생각 없이 안전한 환경에서 사용하다가 릴리스 후 예측할 수 없는 클라이언트 환경에서 뜻하지 않은 오동작을 만날 수 있습니다.<br /> <br /> 다행히 _vsnwprintf_s는 wvnsprintf처럼 동작하는 방식도 지원합니다. 이를 위해 버퍼 수를 _TRUNCATE 전처리 상수로 지정하면 됩니다. (_TRUNCATE는 crtdefs.h파일에 -1로 정의되어 있습니다.)<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > wchar_t buffer[10]; va_list vaList; va_start(vaList, format); int retval = <span style='color: blue; font-weight: bold'>_vsnwprintf_s</span>(buffer, <span style='color: blue; font-weight: bold'>_TRUNCATE</span>, format, vaList); va_end(vaList); </pre> <br /> 위의 코드는 wvnsprintf와 동작 방식이 같습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 정리해 보면 _vsnwprintf_s와 StringCbVPrintfW 함수를 사용하는 것이 권장됩니다. <br /> <br /> 대신 _vsnwprintf_s의 경우 예외 발생으로 인해 주의를 요하는데 디버그 시에는 확실히 문제를 인지할 수 있도록 버퍼를 지정하는 것이 좋고, 릴리스 시에는 _TRUNCATE로 처리하는 것이 좋습니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1848
(왼쪽의 숫자를 입력해야 합니다.)