C와 C++는 구조 내 어레이의 멤버별 할당을 지원하지만 일반적으로는 지원하지 않는 이유는 무엇입니까?
멤버별 어레이 할당은 지원되지 않으므로 다음 기능이 작동하지 않습니다.
int num1[3] = {1,2,3};
int num2[3];
num2 = num1; // "error: invalid array assignment"
언어의 목적은 오픈엔드 프레임워크를 제공하고 어레이 복사 등의 구현 방법을 사용자가 결정할 수 있도록 하는 것이라고 생각하여 이를 사실로 받아들였습니다.
다만, 다음의 조작이 가능합니다.
struct myStruct { int num[3]; };
struct myStruct struct1 = {{1,2,3}};
struct myStruct struct2;
struct2 = struct1;
어레이num[3]instance에서 멤버별로 할당되어 있다.struct1instance에 포함되다struct2.
멤버별 어레이 할당은 구조에서 지원되지만 일반적으로 지원되지 않는 이유는 무엇입니까?
편집: 스레드 std::string in structure의 Roger Pate 코멘트 - 복사/할당 문제?대체적인 방향성을 지적하는 것 같지만, 제가 직접 확인할 수 있을 만큼은 아닙니다.
편집 2: 우수한 반응이 많습니다.나는 그 행동의 이면에 있는 철학적 또는 역사적 근거에 대해 가장 궁금했기 때문에 Luther Blissett's를 선택했지만, 관련된 사양 문서에 대한 James McNellis의 언급도 유용했다.
제 생각은 이렇습니다.
C 언어 개발은 C: 어레이 타입의 진화에 대한 이해를 제공합니다.
어레이의 개요를 설명하겠습니다.
C의 전주자 B와 BCPL에는 다음과 같은 고유한 배열 유형이 없었습니다.
auto V[10] (B)
or
let V = vec 10 (BCPL)
는, V가 메모리의 미사용 영역인 10개의 「워드」를 가리키도록 초기화되어 있는 (입력되어 있지 않은) 포인터라고 선언합니다.B는 이미 사용 중입니다.*포인터 참조를 위해 사용되었으며[]짧은 손 표기법,*(V+i)의미했다V[i]현재의 C/C++와 같이.하지만,V는 배열이 아니라 일부 메모리를 가리킬 필요가 있는 포인터입니다.이것은 Dennis Ritchie가 구조 타입으로 B를 연장하려고 했을 때 문제를 일으켰다.그는 오늘날 C와 같이 어레이를 구조체의 일부로 만들고 싶어했습니다.
struct {
int inumber;
char name[14];
};
그러나 B,BCPL 개념의 어레이를 포인터로 사용했을 경우, 이것은 다음과 같은 작업이 필요하게 됩니다.name실행 시 구조 내 14바이트의 메모리 영역으로 초기화해야 하는 포인터를 포함하는 필드입니다.초기화/레이아웃 문제는 어레이를 특별 취급함으로써 최종적으로 해결되었습니다.컴파일러는 어레이를 포함하는 식을 제외하고 실제로 데이터에 대한 포인터를 필요로 하지 않고 구조, 스택 등에서 어레이의 위치를 추적합니다.이 처리를 통해 거의 모든 B코드가 계속 실행될 수 있으며 "arrays convert to pointer if you see them" 규칙의 소스가 됩니다.오픈사이즈 어레이 등이 가능하기 때문에 매우 편리한 호환성 해킹입니다.
어레이를 할당할 수 없는 이유는 다음과 같습니다.배열은 B의 포인터이므로 간단히 다음과 같이 쓸 수 있습니다.
auto V[10];
V=V+5;
"어레이"를 재설정합니다.배열 변수의 베이스가 더 이상 l값이 아니기 때문에 이 값은 의미가 없습니다.따라서 이 할당은 허용되지 않았으며, 선언된 어레이에서 이러한 기본 설정을 수행한 몇 가지 프로그램을 탐지하는 데 도움이 되었습니다.그리고 나서 이 개념이 고착되었다.배열은 C형 시스템의 일등석 표기가 되도록 설계되지 않았기 때문에 사용하면 포인터가 되는 특수한 짐승 취급이 대부분이었습니다.또, 특정의 관점에서는(C-array가 부실한 해킹이라고 하는 것은 무시됩니다), 어레이의 할당을 거부하는 것은, 다음과 같습니다.오픈 어레이 또는 어레이 함수 파라미터는 사이즈 정보가 없는 포인터로서 취급된다.컴파일러에는 어레이 할당을 생성하기 위한 정보가 없습니다.호환성을 위해 포인터 할당이 필요했습니다.선언된 어레이에 대한 어레이 할당을 도입하면 실제로 문제를 해결하지 않고도 잘못된 할당(a=b 포인터 할당 또는 요소별 복사본입니까?) 및 기타 문제(값으로 어레이를 전달하는 방법?)를 통해 버그가 발생할 수 있습니다. memcpy를 사용하여 모든 것을 명시하십시오.
/* Example how array assignment void make things even weirder in C/C++,
if we don't want to break existing code.
It's actually better to leave things as they are...
*/
typedef int vec[3];
void f(vec a, vec b)
{
vec x,y;
a=b; // pointer assignment
x=y; // NEW! element-wise assignment
a=x; // pointer assignment
x=a; // NEW! element-wise assignment
}
이것은 1978년 C의 리비전으로 구조 할당이 추가되어도 변경되지 않았습니다(http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf).C에서는 레코드가 다른 타입이지만 초기 K&R C에서는 레코드를 할당할 수 없었습니다.memcpy를 사용하여 멤버 단위로 복사해야 하고 포인터만 함수 파라미터로 전달할 수 있었습니다.할당(및 매개 변수 전달)은 이제 단순히 구조체의 원시 메모리의 memcpy로 정의되었으며, 이는 기존 코드를 해제할 수 없기 때문에 쉽게 인용되었습니다.의도하지 않은 부작용으로 어레이 할당이 암묵적으로 도입되었지만, 이는 구조 내부 어딘가에서 발생했기 때문에 어레이 사용 방법에 문제가 될 수 없었습니다.
할당 연산자에 대해 C++ 규격은 다음과 같이 기술되어 있습니다(C++03 5 5.17/1).
할당 연산자가 여러 개 있습니다...모두 왼쪽 피연산자로 수정 가능한 l값이 필요합니다.
어레이는 수정할 수 있는 l값이 아닙니다.
단, 클래스 타입 오브젝트에 대한 할당은 특별히 정의됩니다(「5.17/4」).
클래스 객체에 대한 할당은 할당 복사 연산자에 의해 정의됩니다.
따라서 암시적으로 선언된 클래스에 대한 복사 할당 연산자가 수행하는 작업을 살펴봅니다(1212.8/13).
클래스 X에 대해 암묵적으로 정의된 복사 할당 연산자는 하위 객체의 멤버별 할당을 수행합니다.각 서브 오브젝트는 그 유형에 적합한 방법으로 할당됩니다.
...
-- 서브오브젝트가 배열인 경우 각 요소는 요소 유형에 적합한 방식으로 할당됩니다.
...
따라서 클래스 유형 객체의 경우 배열이 올바르게 복사됩니다.사용자가 선언한 복사 할당 연산자를 제공할 경우 이 기능을 이용할 수 없으므로 요소별로 어레이 요소를 복사해야 합니다.
그 이유는 C(C99 § 6.5.16/2)에서도 비슷하다.
할당 연산자는 왼쪽 피연산자로서 수정 가능한 l값을 가져야 한다.
그리고 §6.3.2.1/1:
수정 가능한 l값은 배열 유형이 없는 l값입니다...[다른 제약이 따른다]
C에서 할당은 C++(66.5.16.1/2)보다 훨씬 간단합니다.
단순 할당(=)에서는 오른쪽 피연산자의 값이 할당식의 유형으로 변환되어 왼쪽 피연산자가 지정한 객체에 저장된 값을 치환한다.
structure-type 객체의 할당에서는 왼쪽 오퍼랜드와 오른쪽 오퍼랜드의 유형이 동일해야 하므로 오른쪽 오퍼랜드의 값은 왼쪽 오퍼랜드에 복사됩니다.
다음 링크에는 어레이 할당 섹션이 있습니다.http://www2.research.att.com/ ~ bs / bs _ bs _ bs _ displays 2 . displays :
어레이의 2가지 근본적인 문제는 다음과 같습니다.
- 배열이 자신의 크기를 모른다.
- 배열의 이름은 아주 작은 자극에도 그 첫 번째 요소에 대한 포인터로 변환된다
이것이 어레이와 구조의 근본적인 차이점이라고 생각합니다.배열 변수는 자기 지식이 제한된 낮은 수준의 데이터 요소입니다.기본적으로 메모리 덩어리와 인덱스를 작성하는 방법입니다.
따라서 컴파일러는 int a[10]와 int b[20]를 구별할 수 없습니다.
그러나 구조에는 동일한 모호성이 없습니다.
네, 다 C/C++ 전문가예요.하지만 저는 이것이 주된 이유라고 생각했습니다.
num2 = num1;
여기서 어레이의 기본 주소를 변경하려고 하는데, 이는 허용되지 않습니다.
그리고 물론 구조2 = 구조1;
여기서 오브젝트 structure1은 다른 오브젝트에 할당된다.
C에서 어레이를 더 이상 보강하지 않은 또 다른 이유는 어레이 할당이 그다지 유용하지 않기 때문일 수 있습니다.이 기능은 C에서 쉽게 얻을 수 있지만(또한 구조의 주소는 단순히 어레이의 주소 또는 어레이의 첫 번째 요소의 주소로 캐스트하여 추가 처리를 할 수도 있습니다) 거의 사용되지 않습니다.한 가지 이유는 크기가 다른 배열이 호환되지 않기 때문에 할당 또는 관련 기능에 대한 값 전달의 이점이 제한되기 때문입니다.
배열이 퍼스트 클래스 유형인 언어에서 배열 매개 변수를 사용하는 함수의 대부분은 임의의 크기의 배열에 대해 작성됩니다.이 함수는 일반적으로 배열이 제공하는 정보인 지정된 수의 요소에 대해 반복됩니다.(물론 C에서는 포인터와 개별 요소 카운트를 건네주는 것이 관용어입니다).특정 크기의 배열을 1개만 수용하는 기능은 그다지 필요하지 않기 때문에 많은 것을 놓칠 수 없습니다.(이는 C++ 템플릿과 같이 발생하는 어레이 크기에 대해 별도의 함수를 생성하도록 컴파일러에 맡길 수 있는 경우 변경됩니다.이것이 바로 이 이유입니다.std::array도움이 됩니다.)
언급URL : https://stackoverflow.com/questions/3437110/why-do-c-and-c-support-memberwise-assignment-of-arrays-within-structs-but-not
'source' 카테고리의 다른 글
| vue-cli 3을 사용하여 두 개의 번들을 별도로 생성하려면 어떻게 해야 합니까? (0) | 2022.08.14 |
|---|---|
| Vue.js 슬롯 내의 템플릿태그를 사용하려면 어떻게 해야 하나요? (0) | 2022.08.14 |
| 왜 sin_addr이 구조체 내부에 in_addr이 있습니까? (0) | 2022.08.14 |
| Java: System.console()에서 입력을 받는 방법 (0) | 2022.08.14 |
| CMake에서의 디버깅과 릴리스 (0) | 2022.08.14 |