Posted by 슴갈
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/34
// 2개의 field를 가지는 enum 타입에 대한 값 체크#define CHECK_INVALID_ENUM_X2(source, case1, case2) \switch (source) \{ \case case1: \case case2: \break; \default: \return false; \}// 3개의 field를 가지는 enum 타입에 대한 값 체크#define CHECK_INVALID_ENUM_X3(source, case1, case2, case3) \switch (source) \{ \case case1: \case case2: \case case3: \break; \default: \return false; \}
enum EA { EA_1, EA_2 };enum EB { EB_1, EB_2, EB_3 };bool SetSomething(EA a, EB b){CHECK_INVALID_ENUM_X2(a, EA_1, EA_2);CHECK_INVALID_ENUM_X3(b, EB_1, EB_2, EB_3);// SetSomethingInternal(a, b);return true;}
#include <stdio.h>int main(){bool r1 = SetSomething(EA(-1), EB_1);bool r2 = SetSomething(EA_1, EB(-1));printf("r1 = %d, r2 = %d\n", r1, r2);return 0;}
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/30
int num_chunk = read(fd, &data, sizeof(data));if (num_chunk < 0)return;num_chunk /= sizeof(data[0]);
int num_chunk = read(fd, &data, sizeof(data))/ sizeof(data[0]);if (num_chunk < 0)return;
ssize_t read(int fd, void *buf, size_t count);
- 양쪽 타입 크기가 같으면 signed 쪽를 unsigned로 변환- 양쪽 타입의 크기가 다르면 작은 쪽을 큰 타입으로 바꾼 뒤unsigned 쪽을 signed 로 변환하여 계산
#include <stdio.h>int main(){{int a = -10;unsigned int b = 10;printf("-10 / 10 = %d\n", a / b);}{short a = -10;unsigned short b = 10;printf("-10 / 10 = %d\n", a / b);}return 0;}
-10 / 10 = 429496728 /* int / unsigned int의 결과 */-10 / 10 = -1 /* short / unsigned short의 결과. */
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/29
void MyClass::SetValue(int value){if (this) // (1){this->m_value = value;}}
MyClass* pMyClass = CreateMyClass(…);// NULL 체크를 하지 않았음pMyClass->SetValue(100);
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/28
ptptomr
2010/12/30 10:24
#
M/D
Reply
Permalink
오옷 오랫만의 posting이군요. 예를들어 주신 것과 같이, 빈번한 사용자 실수가 예상되는 case (missing of checking null pointer) 에 대해 platform이 방어할 수 있는 방법이 없다니 믿기지 않습니다.
doyongid
2011/01/19 08:30
#
M/D
Reply
Permalink
와우. 좋은 내용 감사합니당
summerlight
2011/01/25 11:10
#
M/D
Reply
Permalink
가상 함수를 통한 간접 분기에서 this가 null이거나 해당 타입의 객체가 아니라면 적절한 vtable을 참조할 수 없어서 충돌이 일어납니다. 뭐 그렇다고 해도 거의 모든 컴파일러가 정적으로 결정되는 함수 호출에 대해서는 안전한 코드를 만들긴 하지만요.
표준에서 이렇게 어디에서는 허용하고 어디에서는 안 하는 식의 예외를 두면 혼란스럽기 때문에 this == null인 경우는 일관되게 정의되지 않은 동작을 하도록 한 것으로 알고 있습니다.
summerlight
2011/02/08 12:13
#
M/D
Reply
Permalink
혹시 컴파일러의 명령어 재배치나 혹은 CPU의 비순차 실행 때문에 발생하는 오류 아닐까요? this가 항상 유효하다고 가정하면 수행 효율 증대를 위해 if (this) 내부의 구문부터 투기적으로 수행을 시켜볼 수도 있는데, 여기에서 this가 NULL이라 미정의라능! 하면서 배를 째는 걸지도 모르겠습니다. 저도 예전에 명령어 재배치로 인해 발생한 문제로 (이건 멀티 쓰레드 문제였지만) 고생했던 적이 있습니다. -_-;
며칠 전 팀 사람들과 모여서 SDK 샘플에 사용할
코드를 리뷰 하다가 한가지 의문이 들었다. 헤더에서
const int로 선언한 상수의 instance는 어디에 생기느냐는 것이었다.
헤더라고 해도 결국 *.c / *.cpp 파일이
include하는 목적으로 사용되는 것이기 때문에 결국은 *.c / *.cpp에
직접 선언 한 것과 같아진다. 즉, a.c와 b.c에서 동시에 const 선언된 상수가 있는 헤더 파일을 include 하게 되면 실제로는 같은 이름의 상수가 a.c와 b.c 에 동시에 선언이 된 것이다. 그리고 이것이 static이 아닌 이상은 같은 이름으로 선언된 것이 2개가 되므로
컴파일 에러를 내어야 한다.
일단 실험을 해보았다.
a.h
const int AAAA = 0;
a.c
#include "a.h"
int main()
{
return AAAA;
}
b.c
#include "a.h"
int foo()
{
return AAAA;
}
bash-3.00$ gcc a.c b.c
/cygdrive/c/ykahn/ccQerCRS.o:(.rodata+0x0): multiple definition of `AAAA'
/cygdrive/c/ykahn/cc3HVd2e.o:(.rodata+0x0): first defined here
collect2: ld returned 1 exit status
역시 예상대로 다중 선언에 의한 컴파일 에러가 발생했다.
그럼 여기서 드는 의문은, c++을 배울 때 꽤 앞 쪽에 나오는 이야기 중에는, ‘헤더에 쓰인 #define을 const로
대체하라’라고 되어 있는데 그렇게 해도 문제가 없는 가였다. 기억으로는 c++에서는 헤더에 const를 넣고도 아무리 많은 cpp 파일에서 include를 해도 위와 같은 문제는 없었다는 것이
경험상의 결과였다.
그래서 이 번에는 cpp 파일로 테스트를 해보았다.
a.h
const int AAAA = 0;
a.cpp
#include "a.h"
int main()
{
return AAAA;
}
b.cpp
#include "a.h"
int foo()
{
return AAAA;
}
bash-3.00$ gcc a.cpp b.cpp
bash-3.00$ _
음.. 그 동안 경험한 결과와 같이 이 경우에는 문제없이
컴파일 된다. 이걸 보고 가장 먼저 드는 생각은 일관성의
문제였다. 좋은 스펙은 예외 사항이 최소여야 한다고 생각되었기에 구글링을 통해 이 부분을 검색을 해보았다.
검색 결과 이 경우 c와 c++은 const를 다르게 해석하며 ISO C++ 표준 Sec. 5.2.11.7, Sec. 7.1.5.1 에 그것이
정의되어 있다고 한다. 뭐, 스펙이 그렇다고 하니 더 이상
의문을 가질 필요는 없어졌고 각각의 상수에 대한 주소를 찍어 보면 include 한 개수만의 서로 다른 instance를 가지고 있는
것으로 나타난다.
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/26
조금 예전의 코드를 보다가 나중에 검토를 해 보자는 주석이 달린 코드를 보았다.
그리고 그 때 제시된 문제를 간략하게 만들어 보았다.
#include <stdio.h>
class CRenderMode
{
public:
explicit
CRenderMode(int mode)
{
printf("mode
= %d\n", mode);
}
};
int main()
{
int mode
= 0;
// 아래 것은 출력 안 됨.
CRenderMode state0( int(mode) );
// 나머지 3개는 출력 됨
CRenderMode state_( int((int)mode) );
CRenderMode state1( int(mode+0) );
CRenderMode state2( (int)mode );
return
0;
}
생성자에 파라미터를 넣을 때 int(mode) 라고 하니 원했던 생성자가 안 불렸다는 것인데, 마치 파라미터 없는 생성자를 부를 때 실수로 CRenderMode state0(); 라고 했을 때와 상황이 같다. 이것도 뭔가 스펙이 있는 듯 하지만, 정확한
이유는 모르겠다.
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/24
용맨소녀
2010/08/11 01:42
#
M/D
Reply
Permalink
explicit 가 뭐죠? ㅡ.ㅡ 플머 인생 18년동안 처음보는 단어군요.. (역시 헛살았다는..)
왕풍뎅이
2010/08/12 15:27
#
M/D
Reply
Permalink
http://bischoff.tistory.com/202 이거라는뎅 용만앙
슴갈
2010/08/31 12:36
#
M/D
Reply
Permalink
왕풍뎅이님 링크를 참조하시면 될 것 같고.... 잘 안쓰일 수도 있지만 꼭 필요한 것 중에 하나입니다. (저의 경우에는, 남이 쓰는 SDK를 만들어야 하는 직업이기에 중요하게 생각하는 키워드 이기도 하고요...)
summerlight
2010/10/23 17:59
#
M/D
Reply
Permalink
오랜만에 들릅니다.
위의 경우는 객체 instance의 선언이 아니라 함수 원형을 선언하는 것으로 간주되기 때문에 그렇습니다. 구체적으로는CRenderMode를 반환하고 int형의 인자를 받는 state0라는 함수를 선언한 셈이 되고요. 함수 선언과 객체 instance의 선언 사이의 구분이 서로 모호해서 발생하는 문제죠. C의 유산을 물려 받느라 어쩔 수 없이 발생한 일인 것 같습니다.
그래서 저는 그냥 명시적으로 static_cast를 씁니다. 타이핑이 좀 길어지더라도 C++같이 위험한 언어에서는 최대한 모호함을 배제하는 것이 맞는 것 같습니다...
memset() 함수를 쓰기 위해
include 해야 하는 헤더 파일 때문에 종종 실수를 한다. 나는 아주 예전부터 <memory.h>를 사용해 왔고 대부분의 컴파일러에서는 문제를 일으키지 않았다.
내일 code release를 해야 하는 라이브러리가 있어서 여러
컴파일러에서 최종 문법 테스트를 한 후, 내가 라이선스를 가지지 못한 나머지 컴파일러에 대해서는 다른
분께 빌드를 의뢰했다. 그리고 의뢰 받은 쪽에서는 저
<memory.h>라는 것 때문에 오류가 난다는 통보를 해 줬다. 그래서 나는
즉시 <string.h>로 바꾸라고 메시지를 줬고 나머지 모두 빌드에 성공했다. <memory.h>를 못 찾을 때는 <string.h>를 include하면 된다는 것은 이전부터 알고 있었기 때문에 그렇게 대응한 것이지만 그때까지만 해도 그건 컴파일러의
잘 못이라고만 생각하고 있었다.
자리에 돌아와서 man page와
wikipedia에서 관련된 표준에 대해 조사를 해 보았다. 그런데 전부 다 표준은 <string.h>라고 나와 있었다. 매뉴얼을 제대로 보지
않은 내 잘 못이긴 하지만 대응되는 헤더가 그다지 직관적이지는 못하다는 생각도 동시에 든다.
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/14
struct
{
int* a;
int* b;
int* c;
} a = {0, 0, (int*)1};
printf("%d, %d, %d\n", a.c, a, a.c);
1, 0, 0
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/9
TJ
2009/04/03 08:33
#
M/D
Reply
Permalink
printf를 위해 스택에 데이터를 넣은 것과, printf에서 format string을 해석해서 꺼내는 데이터의 offset이 달라서 생기는 현상이죠?
두번째 파라미터를 a.b나 a.a 등으로 바꾸면 마지막 값도 1로 나올 것 같은데요?
printf한테 두번째도 숫자다.. 하고 %d를 줬지만, 실제 printf에게 전달되는 두번째 인자는 숫자가 아니라 struct a이기 때문에 발생하는 현상으로 보입니다.
TJ
2009/04/09 09:36
#
M/D
Reply
Permalink
struct를 '인자'로 보지않고 primitive type만 '인자'로 생각한다면, 그렇게 생각할 수도 있겠네요.
unsigned long aaa = 0x01FF0002;
unsigned char* pCh = (unsigned char*)&aaa;
unsigned short* pWd = (unsigned short*)(pCh+1);
printf("+++++ %x, %x\n", *pCh, *pWd);
+++++ 2, ff00
+++++ 1, 00ff
+++++ 2, 3d8f
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/8
Mahavishnu
2009/03/06 18:01
#
M/D
Reply
Permalink
엔디안 문제에 대한 정답이 알고싶습니다.
저도 범용 코딩 스타일을 지향하는지라 . .
저런 경우에는 어떤 방식으로 구현하는 것이 좋은지요?
슴갈
2009/03/15 10:30
#
M/D
Permalink
엔디안 문제의 정답은 '항상 원래 정의한 type만 사용하며, 그 type의 각각의 바이트를 제어하기 위해서는 shift와 masking을 이용한다'로 정의하면 되지 않을까 생각합니다. 위의 예의 경우에도 원래의 type인 unsigned long에서 masking으로 값을 뽑아야 하고요.
단, 파일에 저장되는 경우에는 파일 포맷에 사용한 엔디안을 명시해야겠지요.
little endian 명시 예: BMP 파일 등
big endian 명시 예: PNG 파일 등
둘 다 가능하지만 헤더에 명시: JPEG의 EXIF 등
유객주
2011/01/23 19:55
#
M/D
Reply
Permalink
big endian 결과가 +++++ 1, 00ff
로 나왔는데,
제 생각에는
+++++ 1, ff00 이어야 할 것 같은데요.
왜냐하면 big endian일 때 메모리 순서상 01FF0002로 저장되고 ff00 두 바이트를 big endian으로 읽으면 그 순서대로이므로, ff00로 나오지 않을까요?
#include <stdio.h>
int main()
{
unsigned char buffer[2] = {0, 0};
unsigned char* pByte = buffer;
*pByte = 1 + *pByte++;
printf("%d, %d\n", buffer[0], buffer[1]);
return 0;
}
% g++ --version
g++ (GCC) 4.0.1 (Debian 4.0.1-2)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% g++ q.cpp
% ./a.out
1, 0
% g++ q.cpp -O3
% ./a.out
1, 0
$ g++ --version
g++ (GCC) 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ q.cpp
$ ./a.exe
1, 0
$ g++ q.cpp -O3
$ ./a.exe
0, 1
Posted by 슴갈
Trackback URL : http://avej.com/textcube/trackback/7
gos
2009/12/26 07:31
#
M/D
Reply
Permalink
컴파일러 버그는 아닙니다.
http://en.wikipedia.org/wiki/Sequence_point
중간에 보시면
i=i++가 예제로 있고 그 결과가 undefined인 설명이 나와 있습니다.
(저는 g++가 변방의 열악한 컴파일러는 아니라고 생각합니다. ^^;)
슴갈
2009/12/28 09:29
#
M/D
Permalink
오해가 있으셨나 본데, g++이 변방의 컴파일러라는 의미가 이니었습니다. -변방의 컴파일러에는 그런 문제가 많이 보이긴 한데, 이번에는 g++에 대한 이야기를 한다는 의미- 저는 현재 g++ 계열 이외에는 실무에 사용하는 컴파일러가 없을 정도입니다. (문법 체크를 위한 MSVC++ 정도가 더 추가...)
그리고 글 내용에는 적지 않았지만 g++ 4.x 컴파일러가 나온 이후로는 저런 방식의 코딩은 warning을 내었습니다. 그리고 그 warning을 조사하다가 이 부분은 스펙상 undefined라는 것을 알고, g++의 각 버전에 대해 문제점을 체크 하던 중 위와 같은 내용을 발견하게 된 것이고요
당시는 상당한 종류의 컴파일러(변방의 열악한 것을 포함한) 사용하고 있었는데 대부분은 undefined에 대해 내부적인 정책을 가지고 옵션이 변해도 1,0 또는 0,1의 동일한 결과를 유지했지만 cygwin의 g++ 3.4.4만은 옵션에 따라 내부적인 정책이 달라서 이 글을 쓰게 된 것입니다.
GP2X WIZ와 CAANNO와 bada용 게임 개발을 하자
- 슴갈
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 |