C에서는 구조물을 반환할지 또는 구조물에 포인터를 반환할지 어떻게 선택할 수 있습니까?
최근에 C근육에 대해 연구하고 그 많은 라이브러리들을 살펴본 결과, 어떤 것이 좋은 방법인지 확실히 알 수 있었습니다.제가 보지 못한 것은 구조물을 반환하는 함수입니다.
something_t make_something() { ... }
내가 파악한 바로는, 이 「올바른」방법입니다.
something_t *make_something() { ... }
void destroy_something(something_t *object) { ... }
코드 스니펫2의 아키텍처는 스니펫1보다 FAR이 인기가 있습니다.그럼 왜 내가 직접 구조물을 돌려보낼까? 스니펫 1처럼?두 가지 옵션 중 하나를 선택할 때 고려해야 할 차이점은 무엇입니까?
또한 이 옵션은 어떻게 비교됩니까?
void make_something(something_t *object)
something_t
작습니다(읽기:하는 것은 하는 것과 으로 전환합니다.기본적으로 스택마운트 되어 있을 필요가 있습니다.
something_t make_something(void);
something_t stack_thing = make_something();
something_t *heap_thing = malloc(sizeof *heap_thing);
*heap_thing = make_something();
something_t
'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE:
something_t *make_something(void);
something_t *heap_thing = make_something();
★★★★★★★★의 ,something_t
어디에 할당되어 있는지 상관하지 않는 경우:
void make_something(something_t *);
something_t stack_thing;
make_something(&stack_thing);
something_t *heap_thing = malloc(sizeof *heap_thing);
make_something(heap_thing);
ABI를 사용하다★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★그렇지 않은 경우 동적 크기의 구조를 갖는 경우가 있습니다. 는 매우 크다struct
또는 퍼포먼스.
.struct
값을 기준으로 반환하는 것과 거의 같은 속도입니다.struct
커야 할 것 같아요.
사실 속도 때문에 기술 2를 얻을 수 있는 것은 아닙니다.가격에 의한 리턴이 아니라 포인터에 의한 리턴입니다.
ABI abi가가2 abi abi 。「 」가 struct
그리고 다음 버전의 라이브러리는 20개의 필드를 추가합니다.이전 버전의 라이브러리의 소비자는 사전에 수정된 포인터를 건네받으면 바이너리 호환성이 있습니다.종료 후의 추가 데이터struct
그들은 알 필요가 없는 것에 대해 알고 있다.
스택에 반환했을 경우, 발신자는 메모리를 할당하고 있기 때문에, 메모리의 크기에 대해서는 고객의 의견에 동의할 필요가 있습니다.라이브러리가 마지막으로 재구축된 후 업데이트된 경우 스택을 폐기합니다.
기술 2에서는 반환하는 포인터 전후에 추가 데이터를 숨길 수도 있습니다(구조체 끝에 데이터를 추가하는 버전이 변형됨).가변 크기 배열로 구조체를 종료하거나 포인터를 추가 데이터 또는 둘 다 추가할 수 있습니다.
를 원하는 struct
에서는 ABI와 struct
버전 정보를 전달해야 합니다.
그렇게
something_t make_something(unsigned library_version) { ... }
서 ''는library_version
입니다.something_t
이 패킷은 반환될 것으로 예상되며 이 패킷이 처리하는 스택의 양을 변경합니다.이것은 표준 C로는 불가능하지만
void make_something(something_t* here) { ... }
「」입니다.something_t
수 있다version
크기 첫 요소로 하며, 이 필드를 후 ""를 호출해야 ."make_something
.
(「 」를 )something_t
해서 , 의, 이 문의를 하다.version
[ ] 버전의 " " " " 를 판별합니다.something_t
같이 일하고 있어요.
볼 때 하면 안 struct
명령으로 할 수 크기 .실제로는 CPU가 1개의 명령으로 처리할 수 있는 최대 크기보다 작거나 같으면 됩니다.하지만 문체적으로는, 그 때도 그것을 피하는 것이 일반적이다.구조체를 값별로 전달하지 않으면 나중에 구조체에 구성원을 추가할 수 있으며 성능에 영향을 미치지 않습니다.
는 ★★★★★★★★★★★★★★★★★★★★★★★★」void make_something(something_t *object)
C에서 인 방법입니다.할당은 발신자에게 맡깁니다.그것은 효율적이지만 예쁘지는 않다.
단, C 에서는 C가 됩니다.something_t *make_something()
불투명한 타입의 개념으로 만들어져 포인터를 사용할 수 밖에 없기 때문입니다.반환된 포인터가 동적 메모리를 가리키는지 아니면 다른 것을 가리키는지 여부는 구현에 따라 달라집니다.불투명한 타입의 OO는 종종 보다 복잡한 C 프로그램을 설계하는 가장 우아하고 최선의 방법 중 하나이지만, 안타깝게도 이를 알고 관심을 갖는 C 프로그래머는 거의 없습니다.
첫 번째 접근방식의 장점:
- 쓸 코드가 적습니다.
- 여러 값을 반환하는 사용 사례에 대해 보다 관용적입니다.
- 동적 할당이 없는 시스템에서 작동합니다.
- 작은 물체나 작은 물체일 경우 더 빠를 수 있습니다.
- 잊어버려 메모리 누수는 없습니다.
free
.
단점:
- 오브젝트가 크면(예를 들어 메가바이트) 스택오버플로를 일으키거나 컴파일러가 적절하게 최적화하지 않으면 속도가 느려질 수 있습니다.
- 이것이 불가능했던 1970년대에 C를 배웠고 최신 정보를 얻지 못한 사람들을 놀라게 할 수 있다.
- 자신의 일부에 대한 포인터가 포함된 개체에서는 작동하지 않습니다.
좀 놀랐어요.
차이점은 예 1은 스택에 구조체를 작성하고 예 2는 힙에 구조체를 작성하는 것입니다.C, 또는 C++ 코드(실효적으로 C)에서는 대부분의 개체를 힙에 작성하는 것이 관용적이고 편리합니다.C++ 에서는 그렇지 않습니다.대부분 스택 상에 있습니다.그 이유는 스택에 개체를 만들 경우 소멸자가 자동으로 호출되고 힙에 개체를 만들 경우 명시적으로 호출되어야 하기 때문입니다.따라서 메모리 누수가 발생하지 않도록 하는 것이 훨씬 쉬워지고 모든 것이 스택에서 처리되기 때문에 예외를 처리할 수 있습니다.C에서는 디스트럭터를 explictly로 불러야 하며 특별한 디스트럭터 함수의 개념은 없습니다(물론 디스트럭터는 있지만 destroy_myobject()와 같은 이름의 일반 함수일 뿐입니다).
이제 C++의 예외는 벡터, 트리, 해시 맵 등과 같은 낮은 수준의 컨테이너 개체에 대한 것입니다.이들은 힙 멤버를 유지하고 소멸자를 가지고 있습니다.현재 대부분의 메모리 부하가 높은 오브젝트는 크기, ID, 태그 등을 제공하는 몇 개의 즉시 데이터 멤버로 구성되어 있으며 나머지 정보는 STL 구조(픽셀 데이터의 벡터 또는 영어 단어/값 쌍의 맵)로 구성되어 있습니다.따라서 대부분의 데이터는 실제로 C++에 저장되어 있습니다.
그리고 현대 C++는 이 패턴이
class big
{
std::vector<double> observations; // thousands of observations
int station_x; // a bit of data associated with them
int station_y;
std::string station_name;
}
big retrieveobservations(int a, int b, int c)
{
big answer;
// lots of code to fill in the structure here
return answer;
}
void high_level()
{
big myobservations = retriveobservations(1, 2, 3);
}
매우 효율적인 코드로 컴파일할 수 있습니다.큰 관찰 구성원은 불필요한 메이크업 복사본을 생성하지 않습니다.
다른 언어(Python 등)와 달리 C에는 태플이라는 개념이 없습니다.예를 들어, 다음은 Python에서 합법적입니다.
def foo():
return 1,2
x,y = foo()
print x, y
함수foo
는 2개의 값을 태플로서 반환합니다.이러한 값은 에 할당됩니다.x
그리고.y
.
C는 태플이라는 개념이 없기 때문에 함수에서 여러 값을 반환하는 것은 불편합니다.이를 회피하는 한 가지 방법은 값을 유지하는 구조를 정의하고 다음과 같이 구조를 반환하는 것입니다.
typedef struct { int x, y; } stPoint;
stPoint foo( void )
{
stPoint point = { 1, 2 };
return point;
}
int main( void )
{
stPoint point = foo();
printf( "%d %d\n", point.x, point.y );
}
이것은 함수가 구조체를 반환하는 것을 볼 수 있는 하나의 예에 불과합니다.
언급URL : https://stackoverflow.com/questions/40167559/in-c-how-would-i-choose-whether-to-return-a-struct-or-a-pointer-to-a-struct
'programing' 카테고리의 다른 글
Rails Vuejs Webpacker: 인스턴스 변수 데이터 전달 (0) | 2022.08.08 |
---|---|
웹 팩을 사용하여 스타일러스 파일을 전체적으로 가져오기 (0) | 2022.08.08 |
Vuex는 모든 제품 정보와 API 요청 쿼리를 저장합니다. (0) | 2022.08.08 |
계산된 개체와 배열의 두 필드별 정렬 (0) | 2022.08.08 |
Vuejs 앱에서 하이차트 다시 그리기 (0) | 2022.08.08 |