2012-01-19 4 views
0

배열에서 단일 산술 형식으로 단일 항목을 캐스팅 (또는 심지어는 역 참조)하는 이상한 동작이 있습니다. Heres는 감소 된 테스트 케이스배열의 내용을 C에서 산술 형식으로 캐스팅

는 :

*((unsigned short *)(&test2[1])) 

좀 다른 플랫폼 (PIC24 같은 주로 임베디드 플랫폼)에 액세스 위반을 받고 있어요 : 상세

void test1() 
{ 
    unsigned char test[10] = {0}; 
    unsigned long i=0xffffffff; 

    *((unsigned long *)(&test[3])) = i; 


    int it; 

    for (it = 0 ; it < 10 ; it++) 

    { 
     printf("%02x ", test[it]); 

    } 
} 
void test2() 
{ 
    unsigned char test[10] = {0}; 
    unsigned char test2[10] = {0}; 
    test[2]=0xFF; 
    test[3]=0xFF; 

    *((unsigned short *)(&test2[1])) = *((unsigned short *)(&test[2])); 


    int it; 

    for (it = 0 ; it < 10 ; it++) 

    { 
     printf("%02x ", test2[it]); 

    } 
} 

는 주로이 표현입니다.

제 질문은이 C 준수 여부입니까? 나는 C 표준 내에서 아무것도 찾을 수 없지만 아마도 나는 장님 일뿐입니다.

이러한 캐스트 (루프 바이트 - 바이트 복사/언 롤링 등은 의미하지 않음)없이이 작업을 수행하는 다른 방법을 알고 있습니까? 플랫폼의 현재 바이트 순서를 알 필요가없는 위치는 어디입니까?

감사합니다.

답변

5
*((unsigned short *)(&test2[1])) 

이것은 정의되지 않은 동작이므로 정렬 및 앨리어싱 규칙을 위반합니다. 하지 마.

test2 개체는 unsigned char의 배열이며 캐스트를 통해 unsigned short 개체로 액세스하고 있습니다. unsigned char 정렬 요구 사항이 unsigned short 정렬 요구 사항과 동일하다는 보장은 없습니다.

C 표준에서는 6.3.2.3p7 (C99)의 정렬 및 6.5p7의 앨리어싱 규칙에 대한 정보를 찾을 수 있습니다.

= 연산자의 왼쪽에 캐스트가있는 경우에는 항상주의해야합니다.

+0

걱정하지 마세요.하지만 때로는 이상한 일을해야 할 때가 있습니다. C가 당신에게 해줄 수있는 좋은 일입니다. 필자가 보통 그런 식으로'유니온 (union) '을 선호하지만 포인터 캐스트보다 훨씬 깔끔한 솔루션입니다. – cha0site

3

라인 *((unsigned long *)(&test[3])) = i;에는 정의되지 않은 동작이 있습니다. sizeof (long) 및 시스템의 endianness에 따라 다릅니다. 일반적으로 다른 포인터 유형 간에는 변환하지 않아야합니다 (void* 제외).

1

여기서 문제는 정렬되지 않은 액세스를하는 것입니다. 문자가 1 바이트이고 단락이 2 일 경우 (홀수 일 경우), 홀수에 대해 단문 쓰기 연산을 수행합니다. 이것은 항상 지원되는 것은 아니며 액세스 위반 가능성이 가장 높은 이유입니다. 이 작업을 수행하고 싶다면 (실제로는 그렇지 않을 수도 있습니다.) char 배열을 앞에 더 길게 한 다음 첫 번째 char을 사용하지 마십시오 (배열을 0이 아닌 1 인덱스로 처리하십시오). -indexed) 그리고 이것은 아마 이것이 작동하지 않는 플랫폼에서 작동 할 것이지만, 심지어 보장되지는 않습니다.

+0

예, 문제 일 수 있습니다. 그러나 당신은'#pragma pack'으로 그것을 고칠 수 있습니다. 컴파일러는 2 바이트 경계에서'char's를 정렬 할 것입니다. – cha0site

+0

@ cha0site :'#pragma pack'은 구조체 요소 패킹에만 영향을 미친다고 생각합니다. 배열이있는이 경우에는 적용 할 수 없습니다. –

+0

@PaulR : 당신 말이 맞아요. 그러나 [__attribute__ aligned] (http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Variable-Attributes.html) GCC 확장을 사용하면 배열을 정렬 할 수 있습니다. – cha0site