C 언어 에센스 레코드 - 육(구조, 연합, 비트, 비트)

7283 단어
육지
구조
데이터 정렬:
많은 컴퓨터 시스템들이 기본 데이터 유형의 합법적인 주소에 대해 몇 가지 제한을 내렸다. 특정한 유형의 대상의 주소는 반드시 특정한 값 K(일반적으로 2, 4, 8)의 배수가 되어야 한다는 것이다. 이런 정렬 제한은 프로세서와 스토리지 시스템 사이의 인터페이스의 하드웨어 설계를 간소화시켰다.
(왜냐하면 프로세서가 메모리에서 8바이트를 자주 꺼내면 메모리의 메모리 블록 단위가 8바이트이기 때문입니다. 만약 프로세서가 모든 더블 형식 데이터의 주소를 8의 배수로 맞추면 하나의 메모리 조작으로 값을 읽을 수 있습니다! 그렇지 않으면 이미지가 두 개의 메모리 블록으로 나누어질 수 있습니다. 우리는 두 번의 메모리 접근을 실행해야 합니다!)
데이터 정렬을 유지하면 효율성이 향상됩니다.
 
데이터 정렬은 운영체제와 하드웨어와 관련이 있다.
IA32 플랫폼에서 Linux의 정렬 규칙은 2바이트 데이터 형식(예를 들어 short)의 주소는 2의 배수이고 다른 데이터 형식의 주소는 4의 배수이다.
WINDOWS의 정렬 요구는 더욱 엄격하다. n 바이트의 기본 데이터 대상의 주소는 반드시 n의 배수이고 n=2,4,8이어야 한다.이런 요구는 메모리 성능을 향상시켰고, 그 대가로 약간의 공간을 낭비했다.
struct S1
{    int  i ;
     char c ;
     int  j ;
} ; 

//컴파일러는 모든 구조 요소가 정렬 요구를 충족시키기 위해 필드의 분배에 간격을 삽입해야 할 수도 있고 구조 자체는 필드의 시작 주소에 정렬 요구도 있을 수 있다.
(그러므로 필드 i와 j의 4바이트 정렬 요구를 충족시키기 위해 컴파일러는 필드 c와 j 사이에 3바이트의 간극을 삽입한다[메모리 구멍이라고 할 수 있다] 구조의)
구조체 주소의 정렬도 고려해야 한다.
그러므로 구조체의 데이터 정렬은 각 구성원의 정렬 요구를 고려하고 전체 구조체의 정렬 요구를 고려해야 한다.
★그러나 하나의 준칙으로 귀결될 수 있다. 구조체에서 가장 큰 데이터 유형 요소의 정렬을 기준으로 한다.
구조의 총 크기는 최대 요소 정렬의 배수를 충족시켜야 한다
struct S2
{     doubled ;
       int  i ;
       int  j ;
       char c ;
} ;

//구성원 중 최대 데이터 유형을 기준으로 정렬하여 전체 구조의 크기를 계산합니다.최대 정렬 규칙이 충족되었으니 작은 정렬 규칙이 충족됩니다.
이 예에서 d는 8개의 바이트를 차지하고 i와 j는 각각 4개의 바이트를 차지하며 c와 끝부분의 구멍은 모두 8개의 바이트를 차지한다.
왜냐하면 c가 위와 마찬가지로 구멍과 모두 4바이트를 차지하면 구조의 총 크기는 최대 원소가 일치하는 배수를 만족시키지 못하기 때문이다.이렇게 하면 구조체 수조가 있으면 다음 구조체의 첫 번째 위치가 정렬되지 않는다.
(최대 유형 요소의 정렬 크기 단위로 구조의 저장 공간을 분할하면 마지막 전체 저장 공간이 이 단위의 배수라고 생각할 수 있다.)
 
★[데이터 정렬이 엄격한 정도의 크기에 따라 질서정연하게 배열된 구조의 구성원은 경계 정렬로 인한 손실을 최대한 줄일 수 있다]
 
만약 구조 중의 어떤 구성원의 실제 위치를 확인해야 한다면,offsetof 매크로 (stddef.h에 정의됨) 를 사용할 수 있습니다.
offsetof (구조체 유형 이름, 구성원 이름) 는 지정한 구성원이 구조체의 첫 번째 요소 주소에 따른 바이트 수를 되돌려줍니다.
struct S1
{     char   c ;
      double d ;
} ;  // offsetof(struct S1, d) ; 8

 
콤비네이션
연합은 하나의 대상을 여러 종류로 인용할 수 있도록 C 언어를 회피할 수 있는 유형 시스템을 제공했다.
연합의 총 크기는 최대 필드의 크기와 같다.연합은 서로 다른 필드로 같은 메모리 블록을 인용하는 것이다.
어떤 경우, 연합은 매우 유용하지만, 잘못 사용하면, C 언어 형식 시스템이 제공하는 안전 조치를 빙빙 돌려서 오류를 일으키기 쉽다.
 
연합은 초기화될 수 있지만, 이 값은 연합의 첫 번째 구성원 유형이어야 한다.
예: union {inta;charc[4];}x = {5} ;
 
적용:
1, 우리는 하나의 구조 중의 두 개의 서로 다른 필드가 서로 배척된다는 것을 미리 알고 있었다. 그러면 우리는 두 필드를 연합의 일부분으로 성명하여 저장 공간을 줄일 것이다.(비슷한 경우가 많은 구조에서는 공간을 많이 절약할 수 있다)
이 때, 우리는 이 연합의 현재 선택을 표시한 다음에 탭 필드와 이 연합을 포함하는 구조를 만듭니다.
typedef enum { N_LEAF, N_INTERNAL } nodetype_t ;// 
struct NODE_T
{    nodetype_t  type ; // 
     union      // 
     {     struct{ struct NODE_T * left ; structNODE_T * right } internal ;
           double data ;
     } info ;
}  ;

2, ★ 서로 다른 데이터 형식의 비트 모드에 접근할 수 있다
// :float unsigned 
unsigned float2bit ( float f )
{   union
    {    float f ;
         unsigned  u ;
    }tmp ;
    tmp.f= f ;
    return  tmp.u ;
}

//이상에서 우리는 하나의 데이터 형식으로 연합 중의 매개 변수를 저장하고 또 다른 데이터 형식으로 그것을 방문한다.(강제 유형 변환과는 다름)
(실제 대응하는 기계 코드는movl 8(%ebp),%eax
이것은 기계 코드에 유형 정보가 없다는 것을 설명한다. 매개 변수가float이든 unsigned든 모두%ebp 편이량이 8인 곳에 있다. 프로그램은 단순히 그들의 값을 반환값으로 복사하고 어떤 위치도 수정하지 않는다. [강제 유형 전환은 부동점 값과 관련된 전환일 때 위치를 수정한다])
3, 데이터 내부의 바이트 레벨에 깊이 들어가 접근할 수 있다
union
{   double d ;
    unsignedu[2] ;
} tmp ;
tmp.u[0] = x1 ;
tmp.u[1] = x2 ; // double d 4 4 。
( )

[주의: 연합에서 구성원의 길이 차이가 현저하면 구성원을 비교적 짧게 저장할 때 많은 공간을 낭비할 수 있다.
좋은 방법은:
연합에서 서로 다른 구성원을 가리키는 지침을 저장하는 것이지 구성원 자체를 저장하는 것이 아니다. 어떤 구성원이 필요할 때 동적 공간을 분배한다.]
 
비트 세그먼트
C는 컴파일러가 정상적으로 허용하는 것보다 더 작은 공간에 정수 구성원을 포장할 수 있도록 한다.이런 정수 성분은 비트 세그먼트가 되어 구조체의 구성원 성명에서 사칭과 상수 표현식(비트 세그먼트가 차지하는 비트 지정)을 사용하여 지정된다.
(비트레이트는 우리가 특정한 정형의 데이터가 몇 자리를 차지하는지 스스로 정의할 수 있도록 하는 것이고 비트에 대한 해석은 데이터 형식과 같다)
ANSI 표준 C는 비트 세그먼트를 unsigned int,signed int, int 형식으로 허용합니다. 각각 기호가 없는 비트 세그먼트, 기호가 있는 비트 세그먼트, 일반 비트 세그먼트 (기호가 있거나 없는 것일 수도 있습니다) 라고 합니다.
일부 컴파일러는char형을 포함한 모든 정수 형식의 비트를 사용할 수 있습니다.
컴파일러는 비트의 최대 길이를 선택할 수 있으며, 비트가 넘을 수 없는 주소 경계를 지정할 수 있으며, 한 필드가 한 글자의 경계를 넘을 때 다음 글자로 이동할 수 있습니다.
[주의: 주소 찾기 조작부호 & 비트 구성원에 사용할 수 없습니다. 컴퓨터가 임의의 길이의 필드를 편집할 수 없기 때문입니다.]
채우기 정보:
struct s
{     unsigned a :4 ;
      unsigned   :2 ;
      unsigned b :6 ; 
}  ; // 4 。

구조에도 무명위 세그먼트가 포함될 수 있다.이웃 멤버 사이의 채우기로 합니다.
★ 주의: 컴파일러는 글자 (int형 크기) 단위로 비트 구조에 저장 공간을 분배합니다!한 번에 한 글자를 분배하는 공간 (32비트는 32비트) 은 정의된 비트의 수량에 따라 분배되는 것이 아니라 데이터 정렬을 위한 것이다.한 바이트 구조의 전체 정의 공간이 한 글자보다 크면 한 글자를 더 분배합니다.
(이렇게 보면 비트 세그먼트를 사용하면 공간을 절약할 수 없고 낭비할 수도 있다. 단지 한 글자의 내부 비트에 쉽게 접근할 수 있어 구명 접근을 비트까지 깊이 있게 할 수 있다!)
 
물론:char형의 비트를 정의하면 컴파일러는 바이트(char형 크기) 단위로 공간을 분배합니다!
(이렇게 하면 우리는 필요에 따라 두 가지 서로 다른 크기 규격의 비트 구조를 선택할 수 있다)
 
★ 이름 없는 필드에 0 길이를 지정하는 것은 특별한 의미를 가진다. 다른 비트가 이전 비트가 있는 구역으로 포장되어서는 안 된다는 뜻이다.있다면, 그것은 방치될 것이다.
struct s
{   unsigned a :4 ;
    unsigned   :0 ;
    unsigned b :6 ;  
}  ;

[0 길이 필드는 하나의 구분선에 해당하며 앞과 뒤의 필드를 서로 다른 글자 단위로 구분한다.]
고: 위의 unsigneda: 4와 뒤의 구멍이 한 글자의 공간을 차지한다.unsigned b:6 뒤에 있는 구멍과 한 글자의 공간을 차지합니다.unsigned a:4,unsigned b:6 두 구성원은 서로 다른 글자 공간에 속한다.전체 비트 구조는 두 글자 즉 8바이트 공간을 차지한다.
마이그레이션 문제:
비트 세그먼트를 사용하는 프로그램은 이식할 수 없습니다.서로 다른 컴퓨터 플랫폼에서의 실현 결과가 다를 수 있기 때문에 하드웨어(대단소단, 글자 길이)와 컴파일러에 의존한다.
적용:
하나의 구조체 수조에 사용되는데 수조가 너무 크기 때문에 구조체의 구성원들은 메모리를 절약하기 위해 반드시 긴밀하게 포장해야 한다.
(메모리 공간 문제에 있어서 엄격한 요구가 있는 프로그램만 비트레이트를 사용합니다. 일반적인 경우는 사용하지 않습니다!)
 
비트 레벨 작업
비트레이트도 비트레이트 조작 방식의 하나이지만 비트레이트는 이식할 수 없다(단점). 그러나 변수 이름을 통해 비트에 접근할 수 있어 조작이 더욱 간편하고 프로그램이 더욱 뚜렷하다.(장점)
우리는 마스크와 위치 이동 조작을 통해 위치 구역의 기능을 완전히 대체할 수 있고 이식성을 가지고 있다.단지 조작이 비트 구간에 미치지 못할 뿐이다.
(이 두 가지 방법은 모두 위치에서 조작할 수 있고 우리는 상황에 따라 프로그램의 명확성과 이식성 사이에 고려할 수 있다)
 
비트 연산자: 비트에 따라 반~, 왼쪽으로 <<, 오른쪽으로 이동>, 연산 & (논리 곱하기), 또는 연산 |(논리 가), 이차 또는 연산 ^(비트에 따라 가)
[주의: 위치 이동 조작부호의 우선순위 문제]
예t=a<<2+a;a<<2라는 비트 조작에 있어서 우선순위가 덧셈보다 낮기 때문에 이 표현식은't=a<(2+a)'가 되고 우리의 실제 의도는 t=(a<2)+a일 수 있다.
[이위 이동 조작과 관련된 표현식은 우선순위 문제를 경계해야 한다!]
일반적인 비트 작업:
1. 비트의 값을 체크 아웃(체크아웃)합니다.
value & 마스크 (결과가 0이면 0이고 결과가 0이 아니면 1)
2, 특정 비트의 값 설정
① 어느 자리를
value | = 마스크
② 어떤 위치를 0
value &= ~ 마스크
[주의: 위의 마스크는 모두 - 설정할 위치 1, 나머지 위치 0을 의미합니다.]
상기 두 종류의 조작(한 종류는 임의의 위치에 접근할 수 있고, 한 종류는 임의의 위치에 값을 부여할 수 있다)을 조합하면 모든 위치 조작을 실현할 수 있습니다!
마스크 생성
1, 왼쪽 이동 작업(<<)으로 필요한 마스크 생성 가능
예:value & (1<        value  |=  ( 1<value  &= ~(1<2, 모든 마스크를 포함하는 그룹을 미리 계산합니다(빈번한 비트 작업에 사용).
예: unsigned intmasks[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//0번부터 7번까지 모든 마스크입니다.
value & masks[n] ;
 
【연합은 unsigned의 방식으로 임의의 데이터 형식에 접근할 수 있고 비트레이트 조작을 사용할 수 있다. 둘을 결합하면 임의의 데이터 내부의 임의의 비트에 접근할 수 있다. 그것이 어떤 데이터 형식이든지! 이렇게 되면 데이터의 밑바닥 디테일이 남김없이 드러날 수 있고 고급 언어가 세절에 대한 봉인과 은폐도 드러날 수 있다. 이로써 C는 어셈블리의 일부 특성을 갖추게 된다.】
 

좋은 웹페이지 즐겨찾기