2

내가 그것을 C에서 구조의 잘못 정렬 된 멤버에 액세스 확인을 경우 테스트하려는 잘못 정렬 구조체 멤버, 액세스

#include <stdio.h> 

#pragma pack(1) /* force 1 byte alignment */ 

/* either member b or member d is mis-aligned */ 
typedef struct 
{ 
    int b; 
    unsigned char c; 
    unsigned int d; 
}A ; 


int main(int argc, char *argv[]) 
{ 
    A _a = {0}; 
    unsigned int *p = NULL; 
    unsigned int *q = NULL; 


    printf("addr of _a : 0x%08x, size of _a : %u\n", &_a, sizeof(_a)); 

    p = (unsigned int*)(&_a.b); 
    q = (unsigned int*)(&_a.d); 

    /* should this fail ? */ 
    (*p)++ , (*q)++; 

    return 0; 

} 

프로그램이 인해로 충돌합니다 가정의 코드를 참조하십시오 예외가 메모리 정렬 오류로 인해 잘못되었지만 Linux 3.6.11 (GCC 4.7.2), WinXP (MingW), 코드 패드 온라인 컴파일러 ( http://codepad.org/yOoc8ACG)

에서 테스트했습니다. 결과를 설명, 나는 OS가 프로그램을 저장하는 무언가를했는지, VxWorks 또는 일부 다른 운영 체제에서 작동하는지 아직도 의심의 여지가

참고 : 코드는 Intel 기반 컴퓨터에서 실행됩니다!

미리 감사드립니다.

+0

p와 q를 증가시킨 후에 다른 함수로 전달하려고하면 어떻게됩니까? 아니면 그 위치의 메모리에 액세스하려고합니까? –

+1

중복 가능한 [정렬되지 않은 메모리 액세스가 항상 버스 오류를 일으 킵니까?] (0120-336-331) – ecatmur

+0

SPARC에서 실행 . – WhozCraig

답변

1

아마도 인텔 컴퓨터에서 실행 중입니다. x86 아키텍처는 문제없이 정렬되지 않은 액세스를 처리 할 수 ​​있습니다. 하지만 다른 아키텍처에서는 문제가있을 수 있습니다. 아키텍처가 잘못 정렬 된 액세스를 지원하지 않는다고해도, 일종의 CPU 예외 핸들러에서 싱글 바이트 액세스로 잘못 정렬 된 액세스를 에뮬레이트하여 운영 체제가 문제를 해결할 수있는 경우가 있습니다.

테스트 프로그램에 (*p)++(*q)++도 필요하다고 생각합니다.

+0

네, 맞습니다. (* p) ++와 (* q) ++로 바꿔야합니다. – Tracy

0

x86 기반 아키텍처는 잘못 정렬 된 주소에서 단어 액세스 지침을 사용할 수 있다는 점에서 일반적이지 않습니다. 결과 연산은 느리고 원자 적이지 않지만 작동합니다.

프로그램에 #pragma이 포함되면 바로 그 의미가 구현 정의됩니다. 일반적으로 데이터 멤버의 주소를 unsigned int* 변수에 할당하면 구현이 잘못 정렬 될 수 있으므로 "정렬되지 않은"로드에 대한 코드가 생성되지 않습니다. 따라서 중요한 아키텍처의 경우 *p 또는 *q (또는 둘 다)이 작동하지 않습니다.

0

결과는 아키텍처 및 커널 구성에 따라 다릅니다. 일반적으로 x86에서는 약간의 성능 저하로 잘못 정렬 된 데이터에 액세스 할 수 있습니다. 이것은 주로 구형 CPU 제품군과의 호환성 때문입니다.

ARM 및 SPARC에서 동작은 커널 구성에 따라 다릅니다. 이러한 불일치 데이터 액세스는 OS에 의해 금지, 허용 또는 에뮬레이트 될 수 있습니다. 후자의 경우 하드웨어 예외가 커널에 의해 가로 채어지고 일부 OS의 코드 평화로 에뮬레이트됩니다.

컴파일러 버전이 나옴에 따라 더 어려워집니다. 예를 들어, 현대의 GCC는 데이터가 정렬되지 않은 것으로 판단되는 경우 비 정렬 방식으로 (즉, 여러 명령어로) 정렬되지 않은 데이터에 액세스 할 수있는 특수 코드를 생성합니다.

1

위의 답변 중 일부는 "x86이기 때문에 완전히 실패하지 않습니다"라고 말합니다. 내가하는 OS가 없다는 것을 알고 있지만 사용자 모드에서 정렬되지 않은 액세스에 대해 x86 프로세서를 구성 할 수 있습니다 (커널 모드가 아니지만 게시 된 코드는 사용자 모드 코드처럼 보입니다). 하지만 내가 말했듯이 실제로이 비트를 구성하는 단일 OS가 아니라는 것을 알았습니다. 그리고 정렬되지 않은 메모리 액세스에 대해 프로세서가 예상하지 않는 일부 코드가 손상 될 수 있습니다.

정렬되지 않은 액세스의 동작은보기에 관계없이 정의되지 않거나 최상의 구현을 정의합니다. 즉, 이러한 작업의 결과는 스펙트럼의 한쪽 끝에서 "예상대로 작동합니다"에서 "프로그램이 충돌 함"까지의 범위를 의미합니다.그 범위의 중간에 "아마도 충돌하지는 않지만 예상대로 행동하지는 않습니다"라는 옵션이 더 나쁜 것입니다 - 예를 들어, 바로 전에 정렬 된 주소에 해당하는 값을 얻을 수 있습니다 [낮은 메모리 주소] 가져올 것으로 예상되는 데이터 또는 가져 오기가 실제로 올바르게 수행되지만 프로세서를 트래핑하고 여러 단계에서 작업을 수행 한 다음 정렬 된 변형보다 10 배 또는 100 배 더 오래 걸리는 경우 덫. 또한 여러 스레드를 실행하는 경우 변수에 대한 업데이트가 원자 적 방식으로 수행되지 않으므로 "절반의 값, 다른 값의 절반"값을 얻을 수 있으므로 매우 이상한 결과가 발생할 수 있습니다 . 이는 "약간 잘못 될 수는 있지만 즉시 명백한 방식으로 진행되지는 않습니다"라는 잠재적 시나리오의 결정적인 목록은 아닙니다.

제 조언은 다음과 같습니다. 정렬을 망치지 말고, 정렬되지 않은 요소에 액세스하는 코드를 작성하지 않도록 최선을 다하십시오. 아마 돌아와서 조만간 당신을 물을 것입니다 ...