« Previous : 1 : 2 : 3 : 4 : 5 : Next »

컴파일 때 trigraph 에 대한 경고문

오랜만에 멀티플랫폼 빌드에서 특이한 경고를 보았다.
 
sprintf(s, "%s:?-??(??)", mi.pattern.c_str());

위의 코드가 문제의 코드인데, 다음과 같은 경고가 나왔다.
 
warning: trigraph converted to '[' character [-Wtrigraphs]
sprintf(s, "%s:?-??(??)", mi.pattern.c_str());
                 ^
warning: trigraph converted to ']' character [-Wtrigraphs]
sprintf(s, "%s:?-??(??)", mi.pattern.c_str());
                    ^
 
최근에는 거의 생각치도 않던 spec인 trigraph가 여기에 적용된 것인데,
예상을 못했던 것은 따옴표 안의 문장에서도 trigraph가 적용된다는 것이었다.
 
??( 는 [ 로, ??) 는 ] 로 변환이 되니, 문제의 
"%s:?-??(??)"
"%s:?-[]" 가 된다.

Posted by 안영기

2019/05/14 23:24 2019/05/14 23:24
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/52

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

비교적 최근부터, 개인적으로 만든 API server를 돌리면서 자체 app이나 자체 웹 페이지에서 그 기능을 이용하도록 하는 개인 프로젝트를 하고 있었다.

API server를 이용하는 app 중에는 Unity로 만든 것도 2개가 있었는데, 며칠 전에 그 중 하나의 GUI를 업데이트 하는 작업을 하였다. Unity의 테스트는 Windows에서 하기 때문에 개발 시의 테스트는 아무런 문제가 없이 잘 진행되었다. 그리고 최종 타겟 디바이스는 Android이기 때문에 마지막으로 디바이스에서 테스트만 하면 업데이트 테스트는 끝나는 상황이었다.

그런데, 그 중에 일부 기능이 타겟 동작을 하지 않았다.

<상황>
1. Windows에서는 잘 되던 app이 Android 디바이스에서는 제대로 동작하지 않았다.
2. 문제의 부분은 API server를 이용하는 부분이었다.
3. Server 쪽의 로그를 보면 app으로부터 아예 요청이 가지 않았다.
4. Unity 쪽에서 원인을 좁혀가니 www.error 가 "Unknown Error"가 발생하는 문제였다.
5. 네트워크와 관련된 부분은 이번에 code를 손댄 적이 없다.
6. 같은 API 서비스를 이용하는 또 다른 app은 문제없이 구동되고 있다.

흔한 오류 패턴은 아니었기 때문에 제일 먼저는 나의 실수인지를 체크했다.
잘 동작하고 있는 또 다른 app의 네트워크 부분과 diff 툴로 확인을 했지만 문제는 찾을 수가 없었다.

따로 방법이 없다보니 adb의 로그를 봐야 했다.

adb logcat -s Unity ActivityManager PackageManager dalvikvm DEBUG

그리고 유의미해 보이는 로그를 찾았다.

05-12 10:19:12.331 19641 19670 E Unity   : java.io.IOException: Cleartext HTTP traffic to api.******.net not permitted
05-12 10:19:12.344 19641 19657 I Unity   : ERROR: Unknown Error
 
저 'Cleartext HTTP traffic'라는 것이 생소해서 검색을 했더니, '안드로이드 9.0 파이(API level 28)'부터는 TLS 기반의 통신이 아니면 이 에러를 낸다고 한다.

https://android-developers.googleblog.com/2018/04/protecting-users-with-tls-by-default-in.html

즉, HTTP를 HTTPS로 바꾸어야 한다는 것인데, 그렇다고 당장에 server를 HTTPS로 바꾸는 것은 무리이다. 그리고 애시당초 내 쪽에서는 code를 손 댄 적이 없는데 발생하는 것이라서 더 원인을 알아 내야만 했다.

일단 1차적인 원인을 제거하기 위해서 Unity - Project Setting - Player 쪽으로 가서 Android의 빌드 버전을 바꾸기로 했는데 거기서 문제의 원인을 찾았다.
Android의 SDK가 다른 PC와의 작업을 위해서 Target API Level을 Automatic(highest installed) 로 했는데 그것이 문제였다.

최근에, Unity의 개발과는 별도로 또 다른 Android project를 위해 Android Studio를 업그레이드 하고 SDK도 가장 최신인 Pie를 추가로 설치했는데 이것이 문제의 발단이다.
원래는 제일 높은 버전이 27이었지만, 이 작업으로 인해 제일 높은 버전이 28로 바뀌게 되었고, Unity의 app을 Android용으로 재빌드를 하는 순간 API level 28이 적용되어 버린 것이었다.
 
사용자 삽입 이미지
결국 가장 빠른 문제 해결인 다음의 방법으로 해결하였다.
 
사용자 삽입 이미지

Posted by 안영기

2019/05/12 12:12 2019/05/12 12:12
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/51

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

기어2S의 Watchface 제작

(본문 내용은 추후에 넣을 예정)

Tizen 2.3.1 SDK의 wearable profile에는 Watchface App이라는 app 타입을 만들 수 있다.

<<Watchface app으로 등록>>
사용자 삽입 이미지


























<<일반 상태의 시간 출력>>
사용자 삽입 이미지


























<<Ambient 모드의 시간 출력>>
사용자 삽입 이미지


























만드는 방법은 다음의 소스를 참고하면 된다.
smwatch_151005a.7z

다운로드 (451K)



Posted by 안영기

2015/10/05 23:36 2015/10/05 23:36
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/48

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

C++11의 UTF-8, UTF-16, UTF-32 표기법

회사 일을 하면서, 사람들에게 설명을 해 줘도 또 다시 물어 보고 또 물어 보고 하는 것 중에 하나가 '문자 인코딩'이다. 지금은 예전과는 달리 거의 유니 코드로 통일이 되었기 때문에 그나마 많은 비교 설명을 할 필요까지는 없다. 하지만, 그대신에 유니 코드를 표기하는 방법 자체에 대해서는 질문이 많은 편이다.
 
UCS-2, UCS-4, UTF-8, UTF-16, UTF-32 등에 대한 자료가 인터넷에는 널려서 이해를 한다 하더라도, IDE에서 소스를 만드기 위해 사용되는 문자 인코딩, 그 안에서 글자를 출력하기 위한 문자 인코딩, 그리고 실제 그것이 C 코드에 버퍼로 적용되었을 때의 인코딩이 각각 다를 수 있다는 것을 이해 시키기는 아주 힘들다.
 
const char* str = "가나다"
-> VC++에서, 소스는 KSC-5601의 코드로 표현될 수 있고 실제 실행 버퍼에서도 KSC-5601일 수 있다.
-> VC++에서, 소스는 UCS-2의 코드로 표현될 수 있고 실제 실행 버퍼에서는 KSC-5601일 수 있다.
-> Ubuntu vi에서, 소스는 UTF-8의 코드로 표현될 수 있고 실제 실행 버퍼에서는 UTF-8일 수 있다.
 
const wchar_t* str = L"가나다"
-> VC++에서, 소스는 KSC-5601의 코드로 표현될 수 있고 실제 실행 버퍼에서도 UCS-2일 수 있다.
-> VC++에서, 소스는 UCS-2의 코드로 표현될 수 있고 실제 실행 버퍼에서는 UCS-2일 수 있다.
-> Ubuntu vi에서, 소스는 UTF-8의 코드로 표현될 수 있고 실제 실행 버퍼에서는 UTF-32일 수 있다.
 
위의 예를 실제 하나식 돌려 보고 디버거로 버퍼 상태를 본 것은 아니지만, 하여간 위와 같은 상황이 될 수 있다는 것에 대해서 설명하는 것은 아주 힘들다. 특히 OS를 건너 뛰며 코드를 복사를 해 와서 생긴 문제를 가지고 왔을 때는, 그 상황을 설명하려면 더 힘들다.
 
그런데 C++11 표준에서는 ""와 L""로 구분하던 버퍼 문자열의 문자 인코딩 표기법이 좀 더 세분화 되었다.
 
const char* str = u8"가나다";
const char16_t* str = u"가나다";
const char32_t* str = U"가나다";
 
와 같이, 각각 UTF-8, UTF-16, UTF-32 에 대한 표기법이 구체적으로 생겨났다. 이제는 컴파일러별로 그 크기나 문자 인코딩이 다를 수 있었던 wchar_t 에서 벗어나, 좀 더 명확하게 버퍼 문자열의 문자 인코딩을 지정할 수 있는 방법이 생긴 것이다.
 

Posted by 안영기

2015/03/22 21:34 2015/03/22 21:34
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/47

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

동급생2 맵출력 샘플 (Tizen 2.3 ver.)

이전에 Android NDK로 만든 것을 동일한 소스를 이용해 Tizen에서 구동하게 만들었다.
Tizen 2.3 에서 테스트 되었으며 일반적인 방법으로 import 를 하면 된다.

- 게임은 1995~6년도의 원작의 resource를 그대로 사용
  (ELF사에 저작권이 있는 부분입임)
- Cairo를 사용하여 scalability 구현
- 터치 입력을 추가, 스크린의 4 방향의 가장자리를 누르면 유이가 움직임

사용자 삽입 이미지

Tizen 2.3용 동급생 2 맵 출력 샘플 (88.7K)

Posted by 안영기

2014/11/23 01:59 2014/11/23 01:59
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/46

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

대변 파이터 (Tizen 이식作)

이번에는 DOS -> Windows -> WIZ -> CANNOO -> bada 를 거쳐 Tizen 플랫폼에도 대변 파이터를 이식해 보았다.


Tizen용 대변 파이터 (522K)

Posted by 안영기

2013/06/02 22:33 2013/06/02 22:33
Response
0 Trackbacks , 2 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/45

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

동급생2 맵출력 샘플 (android ver.)

이전에 bada로 만든 것을 동일한 소스를 이용해 Android에서 구동하게 만들었다.

android-ndk-r8b 에서 테스트 되었으며 일반적인 NDK 샘플인 것처럼 import 를 하면 된다.


- 게임은 1995~6년도의 원작의 resource를 그대로 사용
  (ELF사에 저작권이 있는 부분입임)
- 당시 4-bit용 게임이었으므로 GetCanvasN()의 포맷인 ARGB8888로 리소스를 변경
- 터치 입력을 추가, 스크린의 4 방향의 가장자리를 누르면 유이가 움직임

Android용 동급생 2 맵 출력 샘플 (182K)

Posted by 안영기

2012/11/18 06:56 2012/11/18 06:56
Response
0 Trackbacks , 2 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/44

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

API의 deprecate 방법

어제 API 관련된 스펙 논의를 하다가 다음과 같은 조건의 해결 방법에 대한 논의가 있었다.
(내용을 핵심만 간략하게 정리한 것)


class IObject
{
};

void RegisterObject(const IObject& obj)
{
}

위와 같은 형태의 API가 기존에 있었을 때, 이 API의 파라미터를 IObject* 로 받도록 바꾸고 싶지만 기존에 이미 만들어진 코드도 제대로 빌드되고 정상 동작하게 하려면 어떻게 해야 하는가?

물론 C 적으로는 다음과 같은 방법이 있을 수 있다.

void RegisterObject(const IObject& obj) __attribute__((deprecated)); // __declspec(deprecated)

void RegisterObject(const IObject& obj)
{
}

void RegisterObject(IObject* obj)
{
}


그리고  나의 경우는 다음과 같은 의견을 내었다.

template <typename T>
struct ParamAdaptor
{
inline ParamAdaptor(const T& obj)
: param(const_cast<T*>(&obj))
{
}

inline ParamAdaptor(T* obj)
: param(obj)
{
}

T* param;
};
class IObject
{
}

void RegisterObject(ParamAdaptor<IObject> objAdaptor)
{
}


이렇게 만들게 되면 다음의 코드가 모두 정상적으로 동작한다.

IObject obj1;
RegisterObject(obj1);
RegisterObject(&obj1);

IObject* obj2 = new IObject;
RegisterObject(*obj2);
RegisterObject(obj2);


물론 이것은 아이디어일뿐, API 사용자가 이 API를 사용할 때 헤더의 선언과의 괴리를 느끼게 되므로 이 방법이 채택되지는 않았다.

Posted by 안영기

2012/08/25 11:10 2012/08/25 11:10
Response
0 Trackbacks , 1 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/43

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

가독성(readability)에 대한 결정

지금 진행하는 프로젝트의 coding idiom에는 가독성(readability)에 대한 부분이 정의되어 있다.


많은 사람들이 관리해야 할 코드에는 가독성이 필요하다는 것에는 의문이 없다. 하지만 무엇이 더 가독성이 좋은가에 대한 의견에는 의문이 많다.


 


1. if 문 뒤에 딱 한 라인이 올 때의 처리


(1) if (cond) 

       return false;


(2) if (cond) 

    {

        return false;

    }


위의 둘 중에 무엇을 택해야 하는 가에는 항상 논란이 많았다. (1)안을 택하게 되면 2개의 라인으로 내용을 모두 볼 수 있다는 장점이 있고 (2)안의 경우에는 indentation에 대한 예외를 두지 않는 규칙이라는 장점이 있다. (코딩에 실수를 할 우려가 있다 등등은 하수를 위한 것이므로 논외) 


현재 내가 진행하는 과제에서는 (2)안이 채택되어 있지만 나는 (1)안을 주장했다. 가독성의 가장 큰 장점이 빨리 코드를 파악해야 한다는 것인데 (1)안처럼 쓰면 한 눈에 코드 2-(2)안을 쓰면 화면 아래에 있을-을 더 볼 수 있다는 장점이 있기 때문이다 

 

 


2. 가로로 긴 줄을 잘라서 개행하기


(1) 가로로 라인이 길어도 개행 하지 않기. 


(2) 128자 등의 기준을 두고 기준 라인이 넘을 경우 개행 권고 


이것도 논란이 많은 이슈 중에 하나다. Linux 쪽의 유명한 사람은 아예 길게 코드를 짤 수 없게 하라는 말도 하였으나 현실과는 좀 맞지 않고, 최근에는 변수 이름을 길게 쓰거나 template을 파라미터로 쓰고 있기 때문에 가로줄이 계속 길어지고 있다.


현재는 가로로 스크롤을 하지 않고도 모든 코드를 다 볼 수 있는 (2)안이 채택되어 있으나 나는 (1)안을 주장하였다. (2)안을 쓰면 코드가 바뀔 때마다 개행 해야 하는 위치를 바꿔야 하는 것이 불편한데다가, 가로로 긴 코드를 실제로 끝까지 봐야 할 일은 거의 없다는 이유에서다.


가로로 줄이 길게 나오려면 주로 파라미터가 많거나 파라미터를 표시하는 방법이 길다는 것인데, 보통 코드를 분석할 때는 앞의 함수 이름을 보고 내가 관심이 있을 때만 뒤의 파라미터까지 보는 것이 대부분이라 나는 (1)안이어도 문제가 없다는 생각이다. 


 


3. 매크로에 대한 것


(1) 매크로가 유리할 때는 써야 한다.


(2) 매크로는 최대한 쓰지 말자. 


이 주제는 goto를 써야 하나 말아야 하냐의 오랜 주제처럼 의견이 많은 내용이다. 하지만 회사의 프로젝트에는 나름대로의 규칙이 존재해야 하기 때문에 이것에 대한 결론도 내어야 하였다. 결론은(2)안이 채택되었으나 나는 아주 예전부터 이것에 관해서는 (1)안을 주장해 왔다. C++ 책에 보면 매크로를 잘 못 썼을 때의 폐혜를 나열하면서 inline template으로 만들라고 한다. 하지만 그것은 매크로를 잘 못 짜거나 잘 못 사용한 경우에 대한 것이므로 제대로 만들었을 때는 문제가 없다는 것이다. 사실 규칙이 (2)안으로 정해졌기 때문에 나도 매크로를 inline template으로 바꾸는 작업을 하였는데, 주로 한 일이 1줄 짜리 매크로를 동일한 기능을 하는 7줄 짜리로 만드는 일이었다. 


그리고 각 method 마다 객체의 validity를 체크 하는 것이 method 제일 앞에 매크로로 들어가 있었다. 매크로만 신뢰한다면 항상 해당 method는 매크로 이후에는 객체 상태가 valid 하다는 것을 보장하는 코드이다. 게다가 수시로 바뀌는 validity 조건을 딱 한군데에서 제어할 수 있기 때문에 큰 장점이 있는 구조였다. 하지만 매크로를 없애야 하는 일이 생기면서 이 부분도 수정을 해야 하게 되었는데 이 매크로 안에는 return과 같은 제어문이 들어 가기 때문에 inline template으로도 만들 수가 없다. 그래서 결국은 매크로를 모두 풀어서 각 method 제일 앞에 넣는 수 밖에 없는 것이다. (물론 이건 안 하고 있다) 


그래서 나는 (1)안을 주장한다. 


Posted by 안영기

2012/05/28 23:17 2012/05/28 23:17
Response
0 Trackbacks , 5 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/42

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

copy constructor 문제?!

정적 분석 툴에서 다음과 같은 코드의 copy constructor에서 잠재적인 문제점이 있다는 보고를 받았다. (코드는 핵심적인 부분만 남긴 것이다)

 

하지만, 이쪽 코드는 우리가 최근 수정한 적이 없기 때문에 다른 모듈에서 최근 새로운 용법이 생기면서 발생한 문제라고 판단하면서 문제 분석을 하였다.

 

 

class A

{

public:

    A(void);

    A(const A& ref);

 

    int m_val;

};

 

A::A(void)

    : m_val(0)

{

}

 

A::A(const A& ref)

{

    m_val = ref.m_val;

}

 

 

확인 결과, 보통은 문제가 없었지만 다음과 같은 형태의 코드가 추가되면서 잠재적인 문제점이 발생한 것이다. (역시 핵심만 추린 것이라 코드 자체의 로직에는 큰 의미가 없다)

 

enum AType

{

    TYPE_DEFAULT

};

 

A GetA(AType type)

{

    switch (type)

    {

    case TYPE_DEFAULT:

        return A();

    }

    // A를 사용하는 쪽에서 return 구문이 없다.

    // enum의 모든 case에 대해서 switch 문에서 처리하므로

    // 정적 분석툴에서는 문제 없는 것으로 인식 한다.

}

 

int main(void)

{

    A a = GetA(TYPE_DEFAULT);

    A b = a;

 

물론 위의 코드만으로는 아무런 문제가 없다. 하지만 누군가가 악의적으로 다음과 같이 사용했을 때가 문제가 된다.

 

    A a = GetA(AType(TYPE_DEFAULT+1));

 

이와 같이 강제로 enum에 정의되지 않은 것을 강제로 넣게 되면 GetA() A를 리턴하긴 하지만 생성자가 불리지 않은 A의 임시 객체를 리턴한다. 그렇게 되면 멤버 변수는 초기화 되지 않은 상태이고 A b = a; 에 의해 copy constructor를 통한 b를 생성한다. 이 때 m_val = ref.m_val; 부분을 지나가게 되는데 a는 초기화된 적이 없으므로 알 수 없는 값인 ref.m_valm_val를 초기화 하기 때문에 최종적으로는 A class copy constructor 문제라고 보고가 된다.


Posted by 안영기

2012/05/28 20:16 2012/05/28 20:16
Response
0 Trackbacks , 0 Comments
RSS :
http://smgal.ismine.net/tc_191/blog1/rss/response/41

Trackback URL : 이 글에는 트랙백을 보낼 수 없습니다

« Previous : 1 : 2 : 3 : 4 : 5 : Next »

블로그 이미지

게임 개발을 기반으로 한, 잡다한 개발 기록 저장소

- 안영기

Notices

Archives

Authors

  1. 안영기

Recent Comments

Recent Trackbacks

Calendar

«   2019/05   »
      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 30 31  

Site Stats

Total hits:
169203
Today:
1
Yesterday:
3