[완료]대입연산에서 함수로부 리턴받은 주소값의 일부를 잘라 먹을 수가 있나요?
글쓴이: next / 작성시간: 금, 2008/03/07 - 4:14오후
static const char *str = "str"; const char *returnStr() { return str; } int main() { const char *result; result = returnStr(); }
위의 코드는 예인데요...
예를 들어 str의 주소가 0x0D502024 인데
result가 가지는 주소값은 0x0D50 가 될 수 있나요?
제가 이런 현상을 겪고 있는데 혹시 이런 현상을 보신적이 있으시거나 원인을 알고 계신분이 있으신가요?
Forums:
정상적인 경우라면
정상적인 경우라면 변하지 않아야합니다.
그런 경우는 어디선가 메모리를 잘못 참조하거나 하여 포인터값이 변경되는 경우입니다..
returnStr함수 내에서 뭔가 잘못된 연산때문에 저 함수라 리턴되면서 잘못된 주소가 들어가는것 같습니다.
저 함수 내부를 잘 살펴보세요.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.
음..말을
음..말을 잘못하신건진 모르겠지만, 적으신 그대로라면 당연히 다릅니다.
같은건 str과 result이지, str의 '주소'(즉 &str)와 result (혹은 &result)가 아니니까요...
혹시 포인터를 리턴하는 함수가 다른 파일과 링크되는 상태라면 가능성이 있습니다.
함수의 본체는 다른 파일에 있는 상황에서 정확한 prototype을 선언하지 않고 함수를 사용하는 경우에는 그런 현상이 발생할 수 있습니다.
보통 prototype이 선언되지 않은 함수의 리턴 값은 integer인 것으로 가정하므로
포인터 형의 크기가 integer 형의 크기보다 클 경우(예를 들어 32-bit 포인터에 16-bit integer를 사용하는 컴파일러)에는 포인터의 값이 손실되는 현상이 발생합니다. (경우에 따라서는 prototype이 없다고 경고가 발생할 수도 있습니다만 컴파일이 중단되지는 않습니다)
잘라먹는 원인은
잘라먹는 원인은 찾았습니다. 그런데 왜 이런건지 어떻게 고쳐야 할지는 좀 더 생각 해 봐야하겠네요.
원인은
예를 들자면 (환경은 little endian 입니다.)
a(0x04000002 번지)에 0x12345678 이라는 주소를 대입하라고 하면
이 녀석이
0x04000000 에 78
0x04000001 에 56
0x04000002 에 34
0x04000003 에 12
를 넣어 버리는 겁니다. 이러니 a가 가리키는 주소를 아무리 찍어 봐도 0x1234 이상은 안 나오는 겁니다. ㅜ.ㅡ
정상적이라면
0x04000002 에 78
0x04000003 에 56
0x04000004 에 34
0x04000005 에 12
가 되어야 한다고 생각 하는데 말이죠..
그렇게 잘리는 거라면..
ARM 같은 환경에서는 충분히 가능성이 있는 얘기 같은데요..
int *ptr = 0x04000002;
*ptr = 0x12345678;
같이 4byte align이 안 된 메모리에 값을 읽거나 쓸 수가 없습니다.
그렇게 쓰려고 할 때 CPU 설정(?)에 따라 두가지 가능성이 있는 걸로 아는데
interrupt(?) 가 발생해서 실행이 중단되거나, 위에 쓰신 것처럼
0x04000000 이라는 주소에 쓰거나 입니다.
정 저렇게 align 안 된 메모리를 사용하고 싶으면
(char *)ptr = 0x78;
(char *)ptr + 1 = 0x56;
이렇게 한바이트씩이나 위의 경우라면 2byte align은 되어 있으니까 short로 2번에
나눠쓰거나 이런 식으로 해야 합니다.
저렇게 할 경우 PC에선 잘 돌아가기 때문에 저도 한번 문제가 일어난 적이 있었죠.
특이한 컴파일러네요.
main()함수에서 result는 4바이트 짜리인 예로 설명하신 것처럼 4의 배수가 아닌 주소에 변수를 할당하지는 않을 것 같습니다.
로컬 변수라 할지라도 저런 바운더리 규칙은 다 따를 것으로 보입니다.
환경에 대해 좀 더 자세히 알려주실 순 없나요?
컴파일러랑 CPU 종류 정도면 될 것 같네요.
그리고 저 소스로는 말씀하신 현상이 벌어질 것 같지 않습니다. 테스트 하신 코드가 저 코드 그대로인지도 확인해주심 좋겠네요.
위의 코드는 단지
위의 코드는 단지 예를 든것이구요.
컴파일러나 cpu 등에 대한 소개 없이도 올린 질문에 대해서 답변 해 주신 분들께 정말 감사드립니다.
cpu는 arm core를 쓰고 있구요, 컴파일러는 ADS 입니다.
원인은 결국에는 찾았습니다.
구조체의 멤버 변수 중에 배열이 있는데 이 배열의 길이가 4byte align이 안되어 있어서 발생했습니다.
즉
typedef struct {
...
char a[30];
char b[32];
...
}A;
과 같이 되어 있는 상태에서 b에는 4byte align 되어 있지 않은 주소가 할당 되면서 위에서 제가 말씀 드린 문제가 발생 했습니다.
그런데 이상한 것은 제가 알기로는 arm에서는 인위적으로 padding을 넣는것으로 알고 있습니다만 이 경우에는 padding 들어가지 않아 오히려 문제가 되는군요 ㅡ.ㅡ;;(구조체의 제일 큰 멤버 변수는 4byte 입니다.)
수정은 일단 배열의 크기를 4의 배수로 맞추어서 했습니다만, 근본적인 해결책이 아닌지라 구조체를 4byte align 하게끔 강제로 설정을 하는 방법을 찾고 있는 중입니다.(확인을 해 보니 강제로 pack시킨 곳은 없는 상태이고 다른 멤버 변수들은 모두 padding을 넣어서 4byte align이 되는데 유독 연속된 배열 두개는 align이 안되는 군요)
__attribute__((aligned(4)) 는 gcc에서만 동작 되는것 같고
#pragma pack(4) 는 적용해서 확인 해 봤는데 제대로 동작을 하지 않는것 같군요.
지금은 이래저래 alignment를 맞출 방법을 찾는 중입니다.
char은 1 byte align이 될겁니다.
ADS는 char과 같은 한 바이트는 바이트 단위, short같은 2 바이트는 2바이트 단위로 align 시킨다고 나오더군요.
char의 배열은 4의 배수로 길이를 안 맞추면 방법이 없더군요.
-zas 옵션이 있던데 이놈이 하는 게 뭔지 정확하게 모르겠더군요.
테스트 해볼려니 귀찮아서 혹 해보셨으면 결과 알려 주심 좋겠네요.
-zas4로 테스트 해
-zas4로 테스트 해 봤는데 여전히 안되는군요.(-zas 옵션은 ARM document에는 deprecated 되었다는 동시에 차기 버전부터는 지원 안된다고 적혀 있는데 현 버전에서도 안되는 건지 아니면 이 다음 버전부터 안된다는 건지 모호 하네요.)
char나 short 이라서 그런건 아닌것 같고 char 배열이 연속되게 나타나는 경우에 일어나는 것 같습니다.
char, short 모두 테스트 해 봤는데 4 byte align이 되더군요.
말씀하신 대로 char 배열의 크기를 4의 배수로 맞추는 수 밖에 없겠네요.
댓글 달기