[C++] bit storage 작성 시 주의사항

pvs-studio 1 를 이용하여 레거시 코드를 검사했을 때 발견한 경고를 기반으로 구성했다.

다음 코드는 8byte bitSet 변수가 for 문의 loop를 돌 때마다 이진수로 표현했을 때 1, 11, 111, 1111, ….. 값이 되길 바라는 코드다. 64번째 돌았을 때 bitSet 변수가 2진수로 1이 64개가 있기를 바랬다.

	
typedef unsigned __int64 BitSetType;

	BitSetType bitSet = 0;
	for (int i = 0; i < 64; ++i)
	{
		BitSetType temp = 1 << i;
		bitSet |= temp;
	}

하지만 i 가 31이 된 루프에서 bitSet 변수는 1이 64개 모두 채워진다. 왜일까.

어셈블리 코드로 확인을 해보니

	
BitSetType temp = 1 << i;
 mov         eax,dword ptr [i]  
 mov         ecx,1  
 mov         dword ptr [rsp+18h],ecx  
 movzx       ecx,al  
 mov         eax,dword ptr [rsp+18h]  
 shl         eax,cl  
 cdqe  
 mov         qword ptr [temp],rax

7번 라인을 실행한 후 eax 가 0x80 00 00 00 값으로,
8번 라인의 cdqe2 명령이 eax(4바이트)를 rax(8바이트)로 변환하면서 sign extension3이 일어나 rax 의 상위 4바이트가 모두 1로 채워졌다.

sign extension 을 막기 위해 처음 코드로 돌아가 6번 라인을 다음과 같이 고쳐보았다.

BitSetType temp = 1u << i;

31번째 루프에서 더 이상 sign extension이 일어나지는 않는다. 하지만 64번 루프까지 모두 마쳤더라도 bitSet 변수는 모두 1로 채워지지 않는다. 이미 위의 어셈블리 코드에서 보고 알았겠지만 unsigned int (위에서는 1u) 를 갖고는 상위 4바이트를 1로 채울 수가 없다. 다음과 같이 변경해야 한다.

BitSetType temp = 1ull << i;

64번의 루프 동안 한 비트씩 잘 채워나가고 생성된 어셈블리 코드도 옳게 보인다.

BitSetType temp = 1ull << i;
 mov         eax,dword ptr [i]  
 mov         ecx,1  
 mov         qword ptr [rsp+18h],rcx  
 movzx       ecx,al  
 mov         rax,qword ptr [rsp+18h]  
 shl         rax,cl  
 mov         qword ptr [temp],rax

결론 : 웬만하면 std::bitset 을 사용하고, 필요하다면 shift 연산자의 왼쪽 값의 타입 지정할 때 주의하자.

  1.  http://www.viva64.com/en/pvs-studio/
  2. http://siyobik.info/main/reference/instruction/CBW%2FCWDE%2FCDQE
  3. http://en.wikipedia.org/wiki/Sign_extension

[C++] 가위 규칙 Scissors rule

Clean Code 를 읽다가 가위 규칙이라는 말이 나와서 찾아보았다.

가위 규칙(Scissors rule)이란?

Write your C++ class header so that the public part is first and the private part is last. You then take a pair of metaphoric scissors and snip off the tail end of a class header file and give the results to users of the class. Everything before the private part is what you need to use the class. This makes it a tad bit easier for readers of a class header to focus in on what they need to know about the class. 

from http://tech.groups.yahoo.com/group/extremeprogramming/message/2405

[ios] 동기화 세션이 시작되지 않았기 때문에

동기화 세션이 시작되지 않았기 때문에 iTunes가 xxx 으로 동기화할 수 없습니다.

라고 뜨고 itunes를 이용한 ipad 동기화가 계속 진행되지 않았다.

한글 검색에서는 해결책을 못찾아서 대충 영문으로 검색하여 발견. 영문으로는 “Sync session fails to start …” 메시지다. itunes 끄고, ipad 케이블에서 뺐다가 끼우고 itunes 켜서 다시 하면 잘될꺼라고. NedNC 님의 답 1 대로 했더니 잘된다.

포스팅하다보니 결국에는 이 링크(http://support.apple.com/kb/TS2529?viewlocale=ko_KR&locale=ko_KR) 를 찾았지만 한글로 검색이 힘들었다. 이럴때는 검색 효율을 위해 에러 메시지에 에러코드도 병기를 잘했으면 싶네.

  1. https://discussions.apple.com/thread/3384205?start=0&tstart=0