void* 연산 도중 생긴 문제
글쓴이: junho park@Google / 작성시간: 화, 2017/03/28 - 3:03오후
안녕하세요. c코딩을 하다가 warning을 만났는데 어떻게 해결할지 모르겠어서 질문을 드립니다.
void *m_log_buffer = pLogger->log_buffer + (pLogCell->opcode != 2) ? pLogger->lastLsn : pLogger->synceLsn;
warning : initialization makes pointer from integer without a cast
여기서 pLogger은 제가 만든 struct이고 pLogger->log_buffer 는 void*, pLogger->lastLsn, pLogger->syncedLsn은 unsigned int로 선언되어 있습니다.
void *m_log_buffer = pLogger->log_buffer + pLogger->lastLsn ;
이코드를 쓰고 있었을 때는 저런 에러가 나지 않았었는데 그 이유도 설명해 주시면 감사하겠습니다.
--수정--
삼항 연산자 우선순위에 관련된 문제라는 것까지는 감을 잡았습니다.
Forums:
참고해보세요.
http://codepad.org/htoZxBvI
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
연산자 우선 순위는 알고 계시고, 포인터와 int의
연산자 우선 순위는 알고 계시고, 포인터와 int의 더하기 빼기는 포인터 연산으로 정의된다는 것도 알고 계실 것 같습니다. 그럼 각 subexpression이 평가되면 결과의 타입이 어떻게 될 지 차근 차근 따라가기만 하면 되지요.
첫 번째 경우:
void* = (int* + int) ? int : int =>
void* = int* ? int : int =>
void* = bool ? int : int =>
void* = int // not ok
두 번째 경우:
void* = int* + int =>
void* = int* // ok
음 ..
+ 가 ?: 보다 우선순위가 높습니다.
결과적으로 m_log_buffer 에는 pLogger->lastLsn 이 들어가게 되니..
pointer 에 integer 를 넣고 있다는 경고가 뜨는거죠.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
삼항 연산자를 쓸 때는 진짜 주의하세요.
삼항 연산자를 쓸 때는 진짜 주의하세요.
우선순위가 일반적으로 생각하는 것보다 굉장히 낮습니다. C언어에서 이 연산자보다 낮은 연산자는 대입 연산자 종류들과 쉼표 연산자밖에 없어요.
삼항 연산자의 조건식 옆에 있는 덧셈 연산자가 먼저 묶이면서 질문자님이 올리신 코드는 이렇게 해석됩니다.
이러면 조건식 부분(
(pLogger->log_buffer + (pLogCell->opcode != 2))
)의 타입과 상관 없이 삼항 연산자의 결과 타입은pLogger->lastLsn
및pLogger->synceLsn
의 타입이 되고, 즉unsigned int
가 됩니다.C언어에서
unsigned int
에서void *
로의 캐스팅이 안 되는 것은 아닙니다만, 명시적인 캐스팅 없이 이렇게 하는 경우는 보통 거의 없기 때문에 컴파일러가 경고를 해 줍니다. 이 경우는 경고를 받아서 천만다행인 경우죠. 프로그래머의 의도와 전혀 다르게 컴파일되고 있으니까요.? 바로 앞에 있는 수식만을 삼항 연산자의 조건식으로 삼으려고 괄호를 쓰셨겠지만, 저것만 감싸서는 의미가 없어요. 이렇게 쓰셨어야죠.
이 경우 삼항 연산자 다음에 덧셈이 일어나고, 즉 타입을 보면
void *
와unsigned int
를 더하게 됩니다. 이러한void *
산술에 대한 C언어 표준적 근거를 못 찾겠는데[1], 결과 타입이void *
이라고 가정해도 크게 무리가 없겠지요. 그 결과 자연스럽게m_log_buffer
에 저장되는 것입니다.이러한 분석은 질문자님의 두 번째 코드
void *m_log_buffer = pLogger->log_buffer + pLogger->lastLsn ;
에도 그대로 적용됩니다.덧. 삼항 연산자 다음으로 우선순위가 낮은 연산자는 논리적 OR(
||
), 그 다음이 논리적 AND(&&
)입니다. 이 둘을 복잡한 수식 가운데서 사용하는 것도 매우 주의해야 합니다.[1] 포인터에 정수를 더하는 표현식은 포인터가 complete object type을 가리켜야만 한다고 되어 있는데,
void
는 incomplete object type이거든요. 뭔가 제가 찾지 못한 예외조항이 있거나 표준에서 이러한 표현식을 허용하지 않는 것 같습니다. 물론 그런 경우에도 컴파일러가 이와 같은 코드를 컴파일해 줄 수 있습니다.댓글 달기