C로만 배열을 포함하는 구조체를 선언하는 이유는 무엇입니까?


131

다음을 포함하는 코드를 발견했습니다.

struct ABC {
    unsigned long array[MAX];
} abc;

이런 선언을 언제 사용하는 것이 합리적입니까?

답변:


184

배열을 값으로 함수에 전달하거나 함수에서 값으로 반환 할 수 있습니다.

이러한 맥락에서 포인터로 붕괴되는 배열과 달리 Structs는 값으로 전달 될 수 있습니다.


1
인라인되지 않은 함수에 대해 16 바이트 또는 32 바이트 이상의 배열로이 작업을 수행하는 것에주의하십시오. 호출자가 이미 tmp 사본을 필요로하지 않는 한 const 참조로 전달하는 것이 더 효율적입니다. 호출 / 반환이 최적화되지 않으면 중간에서 큰 배열 (수천 바이트)이 값을 전달하는 끔찍한 일입니다.
— Peter Cordes

85

또 다른 장점은 크기를 추상화 [MAX]하여 객체를 선언 하는 모든 위치에서 코드 전체 를 사용할 필요가 없다는 것 입니다. 이것은 또한 달성 될 수있다

typedef char ABC[MAX];

그러나 훨씬 더 큰 문제가 있습니다 : ABC배열 유형 이라는 것을 알아야합니다 (type 변수를 선언 할 때 이것을 볼 수는 없지만 ABC) 그렇지 않으면 다른 ABC것을 의미한다는 사실에 찔릴 것입니다 함수 인수 목록과 변수 선언 / 정의에서.

또 다른 장점은 구조체를 사용하면 많은 코드를 다시 작성할 필요없이 필요한 경우 나중에 더 많은 요소를 추가 할 수 있다는 것입니다.


45

구조체를 복사하고 함수에서 구조체를 반환 할 수 있습니다.

구조체의 일부가 아닌 한 배열로는 그렇게 할 수 없습니다!


26

이렇게 복사 할 수 있습니다.

struct ABC a, b;
........
a = b;

배열의 경우 memcpy 함수 또는 루프를 사용하여 각 요소를 할당해야합니다.


6
(따라서 깔끔한 코드를 만들 수 있습니다
— John Carter

3
유용합니다. 불행히도 (a == b)!?! 얼마나 일관성이 없습니다. C ++의 경우 == 연산자를 찾습니다. C에서는 "이진수 =="에 유효하지 않은 피연산자입니다.
— Matt

11

struct를 사용하여 string 과 같은 새로운 유형의 데이터를 만들 수 있습니다 . 당신은 정의 할 수 있습니다 :

struct String {
    char Char[MAX];
};

또는 함수의 인수로 사용하거나 메소드에서 리턴 할 수있는 데이터 목록 을 작성할 수 있습니다. 구조체는 =와 같은 일부 연산자를 지원할 수 있고 배열에 메소드를 정의 할 수 있기 때문에 배열보다 유연합니다.

그것이 당신에게 유용하기를 바랍니다 :)


2
기본적으로 C가 클래스를 만드는 가장 가까운 것입니다. 나는이 대답을 가장 좋아하기 때문에 그것을 좋아합니다.
— 네이트 CK

1
C의 메소드와 같은 것은 C의 구조체가 평범한 오래된 데이터가 아닙니다. 하지 C. ++는 (다른 답변이 작업을 수행 할 수있는 이유는 보여) 기본 의해 지원 = 연산자를 가지고 있지만, 이것은 오해의 소지가 있으며 대부분은 C에 적용
— 조나단 스턴 버그

3
@J Sternberg : "방법"은 서브 루틴이 데이터 "객체"와 관련이 있다고 생각하는 방법입니다. C로 동작하는 "객체"와 "방법"의 "클래스"를 확실히 만들 수 있습니다. 언어는 그러한 것들을 공식적으로 정의하지 않습니다. C에서 더 나은 추상화를 만들고 싶다면 구조체에 물건을 채우는 것이 일반적으로 가장 좋은 방법입니다.
— 네이트 CK

또한 C에서 메소드를 "만들기"를 원한다면 함수 포인터 (예, 예, 까다로운 구문, 데이터 보호 없음 등)를 사용하여 함수를 작동하는 데이터와 연관시킬 수 있습니다. C의 함수 내부 에이 포인터가 자동으로 생성되지 않기 때문에 첫 번째 인수에서 "self"를 전달해야합니다 (원하는 경우 "this"라고도 할 수 있습니다). 물론 체조입니다. C ++에서는 기본적으로 이와 같은 것들이 있지만, 보너스로 숨겨진 오버 헤드가있을 수 있습니다 ...
— BenPen

2

그러한 a를 사용하는 또 다른 장점은 그러한 a 가 사용될 때마다 형식 안전성을 강제struct 한다는 것 입니다. 특히 서로 다른 목적으로 사용되는 동일한 크기의 어레이로 구성된 두 가지 유형이있는 경우 이러한 유형을 사용하면 실수로 어레이를 부적절하게 사용하지 않아도됩니다.struct

에서 배열을 래핑하지 않으면 struct여전히 배열을 선언 할 수 있습니다 typedef. 이로 인해 다음과 같은 장점이 있습니다. struct– 유형이 한 번 선언됩니다. • 크기가 자동으로 정확합니다. 코드는 유지 관리가 용이하지만 ◦ 엄격한 형식 안전성, ◦ 형식의 값을 복사 및 반환하는 기능 및 ◦ 나중에 나머지 코드를 손상시키지 않고 멤버를 추가 할 수있는 기능이 손실됩니다. typedef주어진 유형의 베어 배열에 대해 2 는 크기가 다른 경우에만 다른 유형을 생성합니다. 또한 함수 인수에 typedefwithout 를 사용하면 형식 안전성을 크게 줄이는 *것과 같습니다 char *.

요약하면 :

typedef struct A_s_s { char m[113]; } A_s_t; // Full type safey, assignable
typedef char   A_c_t[113];                   // Partial type-safety, not assignable

A_s_t          v_s(void);     // Allowed
A_c_t          v_c(void);     // Forbidden

void           s__v(A_s_t);     // Type-safe, pass by value
void           sP_v(A_s_t *);   // Type-safe
void           c__v(A_c_t);     // UNSAFE, just means char * (GRRR!)
void           cP_v(A_c_t *);   // SEMI-safe, accepts any array of 113

1

구조에는 OOP 메모리 관리 패러다임의 장점 중 일부를 모방 한 배열 초기화, 복사 및 fini 함수가 포함될 수 있습니다. 실제로, 사용자 정의 구조를 관리하기 위해 sizeof () 구조를 사용하여 정확히 얼마나 많은 바이트가 관리되는지 알 수있는) 일반적인 메모리 관리 유틸리티를 작성하도록이 개념을 확장하는 것은 매우 쉽습니다. C로 작성된 많은 현명한 생산 코드 기반은 이것들을 많이 사용하며 일반적으로 범위가 매우 로컬이 아닌 한 배열을 사용하지 않습니다.

실제로 구조에 내장 된 어레이의 경우이 어레이에 액세스하려고 할 때마다 바운드 검사와 같은 다른 "스마트 일"을 수행 할 수 있습니다. 배열 범위가 매우 제한적이지 않으면 배열 범위를 사용하고 프로그램 전체에 정보를 전달하는 것은 좋지 않습니다. 조만간 밤에 깨어 주말을 망치게하는 벌레가 생길 것입니다.


이것은 왜 배열 만struct 포함 하는 것을 사용할 수 있는지에 대한 질문에는 대답하지 않습니다 .
— PJTraill
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.