programing

혼합 데이터 유형(int, float, char 등)을 어레이에 저장하는 방법은 무엇입니까?

prostudy 2022. 6. 17. 21:39
반응형

혼합 데이터 유형(int, float, char 등)을 어레이에 저장하는 방법은 무엇입니까?

혼합 데이터 유형을 배열에 저장하려고 합니다.어떻게 그럴 수 있죠?

배열 요소를 구분된 결합(태그 부착 결합이라고도 함)으로 만들 수 있습니다.

struct {
    enum { is_int, is_float, is_char } type;
    union {
        int ival;
        float fval;
        char cval;
    } val;
} my_array[10];

type는 멤버 중 하기 위해 됩니다.union는 각 어레이 요소에 사용해야 합니다. 해야 할 int요소는

my_array[0].type = is_int;
my_array[0].val.ival = 3;

배열의 요소에 액세스하려면 먼저 유형을 확인한 다음 해당 유니언 멤버를 사용해야 합니다. a.switch스테이트먼트가 도움이 됩니다.

switch (my_array[n].type) {
case is_int:
    // Do stuff for integer, using my_array[n].ival
    break;
case is_float:
    // Do stuff for float, using my_array[n].fval
    break;
case is_char:
    // Do stuff for char, using my_array[n].cvar
    break;
default:
    // Report an error, this shouldn't happen
}

type는 항상 member에 되어 있는 합니다.union.

결합 사용:

union {
    int ival;
    float fval;
    void *pval;
} array[10];

단, 각 요소의 유형을 추적해야 합니다.

어레이 요소의 사이즈는 같아야 합니다.그래서 가능하지 않습니다.배리언트 타입을 작성하면 회피할 수 있습니다.

#include <stdio.h>
#define SIZE 3

typedef enum __VarType {
  V_INT,
  V_CHAR,
  V_FLOAT,
} VarType;

typedef struct __Var {
  VarType type;
  union {
    int i;
    char c;
    float f;
  };
} Var;

void var_init_int(Var *v, int i) {
  v->type = V_INT;
  v->i = i;
}

void var_init_char(Var *v, char c) {
  v->type = V_CHAR;
  v->c = c;
}

void var_init_float(Var *v, float f) {
  v->type = V_FLOAT;
  v->f = f;
}

int main(int argc, char **argv) {

  Var v[SIZE];
  int i;

  var_init_int(&v[0], 10);
  var_init_char(&v[1], 'C');
  var_init_float(&v[2], 3.14);

  for( i = 0 ; i < SIZE ; i++ ) {
    switch( v[i].type ) {
      case V_INT  : printf("INT   %d\n", v[i].i); break;
      case V_CHAR : printf("CHAR  %c\n", v[i].c); break;
      case V_FLOAT: printf("FLOAT %f\n", v[i].f); break;
    }
  }

  return 0;
}

결합 요소의 크기는 가장 큰 요소의 크기인 4입니다.

연합은 표준적인 방법이다.하지만 다른 해결책도 있습니다.그 중 하나는 태그가 달린 포인터로 포인터의 "자유" 비트에 더 많은 정보를 저장하는 것입니다.

아키텍처에 따라서는 로우비트 또는 하이비트를 사용할 수 있지만, 가장 안전하고 휴대하기 쉬운 방법은 정렬된 메모리를 이용하여 사용하지 않는 로우비트를 사용하는 것입니다.예를 들어 32비트 및 64비트 시스템에서 포인터는 4의 배수여야 합니다(전제로).int는 32비트 타입)이며, 최하위2비트는 0이어야 합니다.을 사용하다물론 포인터를 참조하기 전에 태그 비트를 지워야 합니다., 되어 있는 할 수 .

void* tp; // tagged pointer
enum { is_int, is_double, is_char_p, is_char } type;
// ...
uintptr_t addr = (uintptr_t)tp & ~0x03; // clear the 2 low bits in the pointer
switch ((uintptr_t)tp & 0x03)           // check the tag (2 low bits) for the type
{
case is_int:    // data is int
    printf("%d\n", *((int*)addr));
    break;
case is_double: // data is double
    printf("%f\n", *((double*)addr));
    break;
case is_char_p: // data is char*
    printf("%s\n", (char*)addr);
    break;
case is_char:   // data is char
    printf("%c\n", *((char*)addr));
    break;
}

정렬되어 있는지 할 수 , 「8」등).long long ★★★★★★★★★★★★★★★★★」uint64_t

이 방법에는 데이터가 다른 변수에 저장되지 않은 경우 메모리가 더 필요하다는 단점이 있습니다.따라서 데이터의 유형과 범위가 제한된 경우 값을 포인터에 직접 저장할 수 있습니다.이 기술은 32비트 버전의 Chrome V8 엔진에서 사용되었으며, 주소의 최하위 비트를 검사하여 다른 개체(예: 이중, 큰 정수, 문자열 또는 일부 개체)에 대한 포인터인지 또는 31비트 부호 값(작은 정수라고 함)을 확인합니다.이 경우,intChrome은 단순히 값을 얻기 위해 산술적인 오른쪽 시프트를 1비트로 합니다.그렇지 않으면 포인터가 참조되지 않습니다.


현재 대부분의 64비트 시스템에서는 가상 주소 공간이 64비트보다 훨씬 좁기 때문에 최상위 비트를 태그로도 사용할 수 있습니다.아키텍처에 따라 태그로 사용하는 방법이 달라집니다.ARM, 68k 및 기타 많은 비트를 무시하도록 설정할 수 있기 때문에 세그먼트 장애 등의 걱정 없이 자유롭게 사용할 수 있습니다.위 링크된 Wikipedia 문서:

태그 부착 포인터의 중요한 사용 예로는 ARM64의 iOS 7에서의 Objective-C 런타임, 특히 iPhone 5S에서 사용됩니다.iOS 7에서는 가상 주소는 33비트(바이트 정렬)이므로 워드 정렬 주소에서는 30비트(3개의 최하위 비트는 0)만 사용하고 태그에는 34비트를 남깁니다.Objective-C 클래스 포인터는 단어와 일치하며 태그 필드는 참조 카운트를 저장하고 객체에 소멸자가 있는지 여부 등 다양한 목적으로 사용됩니다.

이전 버전의 MacOS에서는 데이터 개체에 대한 참조를 저장하기 위해 Handles라는 태그가 지정된 주소를 사용했습니다.주소의 상위 비트는 데이터 개체가 각각 잠겨 있는지, 삭제 가능한지 또는 리소스 파일에서 생성되었는지 여부를 나타냅니다.이로 인해 MacOS 어드레싱이 시스템7에서 24비트에서 32비트로 향상되었을 때 호환성 문제가 발생했습니다.

https://en.wikipedia.org/wiki/Tagged_pointer#Examples

x86_64에서는 여전히 높은 비트를 태그로 주의하여 사용할 수 있습니다.물론 이 16비트를 모두 사용할 필요는 없으며 향후 검증에 사용할 때 일부 비트를 생략할 수도 있습니다.

이전 버전의 Mozilla Firefox에서는 유형(int, string, object...)을 저장하는 데 사용되는 3개의 낮은 비트와 함께 V8과 같은 작은 정수 최적화도 사용합니다.그러나 JégerMonkey 이후 다른 경로(Mozilla의 새로운 JavaScript표현, 백업 링크)를 선택했습니다.이 값은 항상 64비트 배 정밀도 변수에 저장됩니다.언제?double정규화된 것이며 계산에 직접 사용할 수 있습니다.그러나 상위 16비트가 모두 1s인 경우, 하위 32비트는 주소(32비트 컴퓨터)를 값 또는 값에 직접 저장하고 나머지 16비트는 유형을 저장하기 위해 사용됩니다.이 기술은 NaN 박싱 또는 Nun Boxing이라고 불립니다.또한 64비트 WebKit의 JavaScriptCore와 Mozilla의 SpiderMonkey에도 사용되며 포인터는 하위 48비트로 저장됩니다.주요 데이터 유형이 부동 소수점일 경우, 이것이 최고의 솔루션으로 매우 뛰어난 성능을 제공합니다.

위의 기술에 대한 자세한 내용은http://https://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations 를 참조해 주세요.

하면 요.void * array, 로 은 " " " 입니다.size_t.을 사용법
어떤 방법으로든 정보 유형을 유지해야 하는 경우 int의 세 번째 배열(int는 열거된 값)을 유지합니다. 다음에 , 던지다, 던지다, 던지다에 나오는 .enumdiscloss.discloss 。

IMO가 내부 결합을 제거함으로써 사용하는 태그 결합(이름에 관계없이)을 정의하는 다른 스타일이 있습니다.이것은 이벤트와 같은 X 윈도 시스템에서 사용되는 스타일입니다.

에서는 Barmar라는 .val 에서는 Sp으로 조합하여 Sp.를 지정..val.변종.안타깝게도 "익명의" 내부 구조와 결합은 C89 또는 C99에서 사용할 수 없습니다.컴파일러 확장기능이기 때문에 기본적으로 휴대할 수 없습니다.

IMO는 전체 정의를 뒤집는 것이 더 좋은 방법입니다.각 데이터 유형을 자체 구조로 만들고 각 구조에 태그(유형 지정자)를 넣습니다.

typedef struct {
    int tag;
    int val;
} integer;

typedef struct {
    int tag;
    float val;
} real;

그런 다음 이것들을 최상위 연합으로 포장합니다.

typedef union {
    int tag;
    integer int_;
    real real_;
} record;

enum types { INVALID, INT, REAL };

지금 우리가 같은 말을 반복하는 것처럼 보일 수도 있고, 그렇게 되고 있습니다.그러나 이 정의는 단일 파일로 분리될 수 있습니다.하지만 우리는 중간을 특정하는 소음을 없앴다..val.데이터를 입수하기 전에 말이죠.

record i;
i.tag = INT;
i.int_.val = 12;

record r;
r.tag = REAL;
r.real_.val = 57.0;

대신에, 그것은 덜 불쾌한 마지막에 간다.:D

이것이 허용하는 또 다른 것은 일종의 상속이다.편집: 이 부품은 표준 C는 아니지만 GNU 확장자를 사용합니다.

if (r.tag == INT) {
    integer x = r;
    x.val = 36;
} else if (r.tag == REAL) {
    real x = r;
    x.val = 25.0;
}

integer g = { INT, 100 };
record rg = g;

업캐스팅과 다운캐스팅.


편집: C99 지정 이니셜라이저를 사용하여 이들 중 하나를 구성하는지 확인해야 합니다.모든 멤버 이니셜라이저는 같은 유니언 멤버를 경유해야 합니다.

record problem = { .tag = INT, .int_.val = 3 };

problem.tag; // may not be initialized

.tag컴파일러에 될 수 는 "Intitializer"가 "Intitializer"이기 때문입니다.왜냐하면.int_에일리어스 뒤에 같은 데이터 영역이 있는 이니셜라이저.레이아웃(!)을 알고 있어도 괜찮습니다.아니, 그렇지 않아.대신 "internal" 태그를 사용합니다(외부 태그와 겹쳐지지만 컴파일러에 혼란을 주지 않습니다).

record not_a_problem = { .int_.tag = INT, .int_.val = 3 };

not_a_problem.tag; // == INT

언급URL : https://stackoverflow.com/questions/18577404/how-can-mixed-data-types-int-float-char-etc-be-stored-in-an-array

반응형