함수 오버로드에만 C ++ 컴파일러를 사용하는 것은 나쁜 습관입니까?


60

그래서 특정 프로세서에 C를 사용하여 소프트웨어 설계를 진행하고 있습니다. 툴킷에는 C와 C ++를 컴파일하는 기능이 포함되어 있습니다. 내가하고있는 일에 대해이 환경에서 사용할 수있는 동적 메모리 할당이 없으며 프로그램은 전반적으로 매우 간단합니다. 이 장치에는 프로세서 전원이나 리소스가 거의 없다는 점은 말할 것도 없습니다. C ++을 전혀 사용할 필요가 없습니다.

즉, 함수 오버로드 (C ++의 기능)를 수행하는 곳이 몇 군데 있습니다. 몇 가지 다른 유형의 데이터를 보내야하며 printf일종의 %s(또는 다른) 인수로 스타일 서식을 사용하고 싶지 않습니다 . 나는 C ++ 컴파일러에 액세스 할 수없는 사람들을 보았지만 printf내 경우에는 C ++ 지원이 가능합니다.

이제 왜 함수를 오버로드 해야하는지에 대한 질문을받을 수 있다고 확신합니다. 지금 당장 그 대답을 드리겠습니다. 직렬 포트로 다른 유형의 데이터를 전송해야하므로 다음과 같은 데이터 유형을 전송하는 과부하가 발생합니다.

unsigned char*
const char*
unsigned char
const char

나는이 모든 것을 처리하는 하나의 방법을 사용하지 않는 것을 선호합니다. 난 그냥 시리얼 포트를 전송하고자하는 기능을 호출 할 때 나는 거의 싶지 않아, 그래서 나는 많은 자원이없는 뭐든지 내 전송 만합니다.

다른 사람이 내 프로그램을보고 "왜 CPP 파일을 사용하고 있습니까?" 이것이 나의 유일한 이유입니다. 그 나쁜 연습입니까?

최신 정보

몇 가지 질문에 답하고 싶습니다.

딜레마에 대한 객관적인 답변은 다음에 달려 있습니다.

  1. C ++를 사용하면 실행 파일의 크기가 크게 증가하는지 여부

현재로서는 실행 파일의 크기가 프로그램 메모리의 4.0 % (5248 바이트 중)와 8.3 %의 데이터 메모리 (342 바이트 중)를 소비합니다. 즉, C ++로 컴파일하는 중입니다 ... C 컴파일러를 사용하지 않았기 때문에 C의 모양이 무엇인지 모르겠습니다. 나는이 프로그램이 더 이상 성장하지 않을 것이라는 것을 알고 있으므로 자원이 얼마나 제한되어 있는지 나는 거기에 괜찮다고 말할 것입니다 ...

  1. C ++를 사용하는 경우 성능에 눈에 띄는 부정적인 영향이 있는지 여부

글쎄, 나는 아무것도 눈치 채지 못했지만 ... 그럼 다시 이해하지 못하기 때문에이 질문을하는 이유가 될 수 있습니다.

  1. C 컴파일러 만 사용 가능한 다른 플랫폼에서 코드를 재사용 할 수 있는지 여부

나는 이것에 대한 대답이 확실히 아니오 라는 것을 안다 . 우리는 실제로 다른 프로세서로 옮기는 것을 고려하고 있지만 더 강력한 ARM 기반 프로세서 (C ++ 컴파일러 툴 체인을 가지고 있음).


59
//의견 을 가질 수 있도록 C 기능 만 사용하는 프로젝트에 C ++을 사용하는 것으로 알려져 있습니다 . 작동한다면 왜 안 되겠습니까?
Jules

76
나쁜 관행은 제공하지 않는 기능을 잘 사용하면 자신을 C로 제한하는 것입니다.
Jerry Coffin

35
"C ++ 컴파일러 사용"이라고 말하면 "C ++ 사용"을 의미합니다. 그냥 말해. C ++ 컴파일러로 C를 컴파일 할 수는 없지만 실제로 C에서 C ++로 쉽게 전환 할 수 있습니다 .
user253751

4
"내가하고있는 일에 대해 프로세서에는 동적 메모리 할당이 없으며 프로그램은 전체적으로 상당히 단순하다. 장치에 프로세서 전력이나 리소스가 거의 없다는 것은 말할 것도 없다. 실제로 C ++을 사용할 필요는 없다"고 그는 덧붙였다. 나는이 두 문장 중 첫 번째 문장이 C ++을 사용하지 않는 이유라고 생각합니다. 왜냐하면 그것들은 꽤 나쁜 문장이기 때문입니다. C ++은 임베디드 시스템에서 사용하기에 완벽합니다.
Pharap

21
@Jules 나는 당신이 이것을 알고 있고 오래 생각하고 있다고 확신하지만, 누군가 이것을 읽지 않는다면 : //C99 이후 C 표준에 의견이있었습니다.
Davislor

답변:


77

나는 "나쁜 연습"을 전화로 지금까지 이동하지 않을 것 자체 하지만 나도 그것이 정말 문제에 적합한 솔루션입니다 확신합니다. 네 가지 데이터 유형을 수행하는 네 개의 개별 함수 만 있으면 C 프로그래머가 옛날부터하지 않은 이유는 무엇입니까?

void transmit_uchar_buffer(unsigned char *buffer);
void transmit_char_buffer(char *buffer);
void transmit_uchar(unsigned char c);
void transmit_char(char c);

그것은 실제로 C ++ 컴파일러가 어쨌든 뒤에서하고있는 일이며 프로그래머에게는 그렇게 큰 오버 헤드가 아닙니다. "C ++ 컴파일러로 not-quite-C를 작성하는 이유"의 모든 문제를 피할 수 있으며, 프로젝트의 어느 누구도 C ++의 어떤 비트가 "허용"되고 어떤 비트가 허용되지 않는지 혼동하지 않을 것입니다.


8
왜 전송되지 않는 유형이 (구체적으로) 구현 세부 사항이므로 왜 숨기고 컴파일러가 구현 선택을 처리하게하면 더 읽기 쉬운 코드가 될 수 있습니다. 그리고 C ++ 기능을 사용하면 가독성이 향상된다면 왜 그렇지 않습니까?
Jules

29
#defineC11_Generic
Deduplicator를

16
@Jules 프로젝트에서 어떤 C ++ 기능을 사용할 수 있는지에 대해 매우 혼란 스럽기 때문입니다. 객체를 포함하는 잠재적 변경이 거부됩니까? 템플릿은 어떻습니까? C ++ 스타일 주석? 물론 코딩 스타일 문서로 해결할 수는 있지만 함수 오버로드의 단순한 경우라면 C를 작성하십시오.
Philip Kendall

25
@Phillip "C ++ 스타일 주석"은 10 년 넘게 유효한 C였습니다.
David Conrad

12
@ 줄 (Jules) : 전송되는 유형이 보험 견적을하는 소프트웨어에 대한 구현 세부 사항 일 수 있지만 OP 애플리케이션은 직렬 통신을 수행하는 임베디드 시스템 인 것으로 들리는데, 여기서 유형 및 데이터 크기가 매우 중요합니다.
whatsisname

55

C ++의 일부 기능 만 사용하고 C로 처리하는 것은 흔하지는 않지만 듣지 못하는 것도 아닙니다. 실제로 일부 사람들 은 더 강력하고 강력한 유형 검사를 제외하고 모든 C ++에서 기능을 사용 하지 않습니다 . 그들은 단순히 C를 작성하고 (C ++과 C의 공통 교차점에서만 작성하도록주의를 기울임) 유형 검사를 위해 C ++ 컴파일러와 코드 생성을 위해 C 컴파일러를 사용하여 컴파일합니다 (또는 C ++ 컴파일러를 항상 사용합니다).

리눅스는 사람들 이 C ++ 컴파일러로 리눅스를 컴파일 할 수 있도록 식별자 classklass또는 로 바꾸 라고 정기적으로 요구하는 코드베이스의 예입니다 kclass. 물론, C ++의 주어진 리누스의 의견 , 그들은 항상 격추 "C ++ - 깨끗한 C"- D GCC는 첫째로 변형 된 코드베이스의 예이며, 점차 더 C ++ 기능을 사용하는 리팩토링.

당신이하고있는 일에는 아무런 문제가 없습니다. C ++ 컴파일러의 코드 생성 품질에 대해 편집증이 있다면 Comeau C ++와 같은 컴파일러를 사용하여 대상 언어로 C를 컴파일 한 다음 C 컴파일러를 사용할 수 있습니다. 그렇게하면 코드를 검사하여 C ++를 사용하여 예상치 못한 성능에 민감한 코드가 삽입되는지 확인할 수 있습니다. 그래도 오버로딩의 경우가 아니어야합니다. 문자 그대로 다른 이름의 함수 (IOW)를 자동으로 생성하므로 정확히 C에서 수행하는 작업입니다.


15

딜레마에 대한 객관적인 답변은 다음에 달려 있습니다.

  1. C ++를 사용하면 실행 파일의 크기가 크게 증가하는지 여부
  2. C ++를 사용하는 경우 성능에 눈에 띄는 부정적인 영향이 있는지 여부
  3. C 컴파일러 만 사용 가능한 다른 플랫폼에서 코드를 재사용 할 수 있는지 여부

질문에 대한 대답이 "예"이면 다른 데이터 유형에 대해 다른 이름의 함수를 작성하고 C를 사용하는 것이 좋습니다.

모든 질문에 대한 대답이 "아니오"라면 C ++을 사용하지 말아야 할 이유가 없습니다.


9
필자는 두 언어의 공유 하위 집합으로 작성된 코드에 대해 C 컴파일러보다 훨씬 나쁜 코드를 생성하는 C ++ 컴파일러를 본 적이 없다고 말해야합니다. C ++ 컴파일러는 크기와 성능 모두에 대해 나쁜 평판을 얻지 만 내 경험은 항상 문제를 일으킨 C ++ 기능을 부적절하게 사용한다는 것입니다 ... 특히 크기에 대해 걱정이 있다면 iostream을 사용하지 말고 사용하지 마십시오. 템플릿이지만 그렇지 않으면 괜찮을 것입니다.
Jules

@ Jules : 가치가있는 것 (많지 않은 IMO)을 위해 C와 C ++ (메모리가 제공되는 경우 Turbo C ++ 1.0, 메모리가 제공되는 경우)에 대한 단일 컴파일러로 판매 된 것이 동일한 입력에 대해 상당히 다른 결과를 생성하는 것을 보았습니다. 그러나 내가 이해하는 것처럼, 이것은 자신의 C ++ 컴파일러를 끝내기 전이었습니다. 따라서 외부에서 하나의 컴파일러처럼 보였지만 실제로는 두 개의 완전히 다른 컴파일러 (하나는 C, 다른 하나는 C ++)가있었습니다.
Jerry Coffin

1
@JerryCoffin 메모리가 제공되는 경우 Turbo 제품은 큰 명성을 얻지 못했습니다. 그리고 1.0 버전 인 경우 고도로 정제되지 않았다는 이유로 변명 될 수 있습니다. 따라서 아마도 그리 대표적이지 않을 것입니다.
Barmar

10
@Barmar : 사실, 그들은 꽤 오랫동안 명성을 얻었습니다. 그들의 나쁜 평판은 주로 자신의 나이 때문입니다. 그들은 같은 빈티지의 다른 컴파일러와 경쟁하지만 gcc 1.4 (또는 무엇이든)로 작업을 수행하는 방법에 대한 질문을 게시하는 사람은 없습니다. 하지만 당신 말이 맞아요. 아주 대표적이지는 않습니다.
Jerry Coffin

1
@Jules 나는 템플릿조차 괜찮다고 주장한다. 널리 알려진 이론에도 불구하고 템플릿을 인스턴스화해도 코드 크기가 암시 적으로 증가하지는 않지만 일반적으로 템플릿의 함수를 사용할 때까지 (크기 증가가 함수 크기에 비례 할 때) 또는 템플릿이 아닌 경우 코드 크기는 증가하지 않습니다. 정적 변수 선언. 인라인 규칙이 여전히 적용되므로 모든 함수가 컴파일러에 의해 인라인되는 템플릿을 작성할 수 있습니다.
Pharap

13

C ++로 컴파일하면 더 많은 기능에 액세스 할 수있는 것처럼 질문을 제기합니다. 그렇지 않다. C ++ 컴파일러로 컴파일한다는 것은 소스 코드가 C ++ 소스로 해석되고 C ++이 C와 다른 언어 라는 것을 의미합니다. 두 개는 유용한 프로그래밍을하기에 충분히 큰 공통 서브 세트를 가지고 있지만 각각 다른 하나에는없는 기능이 있습니다. 두 언어 모두 허용되지만 다르게 해석되는 코드를 작성할 수 있습니다.

진정으로 원하는 것이 함수 오버로드라면 C ++을 가져 와서 문제를 혼란스럽게하는 요점을 실제로 보지 못합니다. 동일한 이름의 다른 함수 대신 매개 변수 목록을 구별하고 다른 이름의 함수를 작성하십시오.

객관적인 기준은

  1. C ++를 사용하면 실행 파일의 크기가 크게 증가하는지 여부

실행 파일은 C ++로 컴파일 할 때 비슷한 C 코드와 비교하여 약간 더 클 수 있습니다. 최소한 C ++ 실행 파일은 심볼이 실행 파일에 유지되는 한도 내에서 모든 함수 이름에 대한 C ++ 이름 관리의 모호한 이점을 갖습니다. (실제로 과부하를 제공하는 것은 사실입니다.) 차이가 귀하에게 중요 할만큼 충분히 큰지 여부는 실험으로 결정해야하는 것입니다.

  1. C ++를 사용하는 경우 성능에 눈에 띄는 부정적인 영향이 있는지 여부

설명하는 코드와 가상의 순수 C 아날로그에 대해 눈에 띄는 성능 차이를 볼 수 있을지는 의문입니다.

  1. C 컴파일러 만 사용 가능한 다른 플랫폼에서 코드를 재사용 할 수 있는지 여부

C ++로 빌드하는 코드를 다른 코드에 연결 하려면 다른 코드도 C ++로 작성하고 C ++로 빌드해야합니다. ( "C"연결을 선언하여) 자신의 코드로 특별 제공하기 위해 오버로드 된 기능에 대해 전혀 할 수 없습니다. 반면에 코드가 C로 작성되고 C로 컴파일되면 다른 사람들이 C 및 C ++ 모듈 모두와 코드를 연결할 수 있습니다. 이런 종류의 문제는 일반적으로 테이블을 돌려서 극복 할 수 있지만 실제로 C ++이 필요하지 않은 것 같습니다. 왜 그런 문제를 먼저 받아 들여야합니까?


4
"C ++로 컴파일 할 때 실행 파일에 기호가 유지되는 정도까지 실행 파일이 약간 더 클 수 있습니다." 그러나 공정한 최적화 툴체인에는 이러한 릴리스를 "릴리스"빌드에서 제거 할 수있는 링커 옵션이 있어야합니다. 즉, 디버깅 빌드 만 부풀려 야합니다. 나는 그것이 큰 손실이라고 생각하지 않습니다. 실제로, 그것은 종종 혜택입니다.
코디 그레이

5

과거에는 C ++ 컴파일러를 "더 나은 C"로 사용하는 것이 사용 사례 로 승격 되었습니다. 사실, 초기 C ++는 바로 그 것입니다. 기본 디자인 원칙은 원하는 기능 만 사용할 수 있으며 사용하지 않은 기능의 비용은 발생하지 않는다는 것입니다. 따라서 ( overload키워드 를 통해 의도를 선언하여) 함수를 오버로드 할 수 있으며 프로젝트의 나머지 부분은 제대로 컴파일 될뿐만 아니라 C 컴파일러가 생성하는 것보다 더 나쁘지 않은 코드를 생성합니다.

그 이후로 언어는 다소 분기되었습니다.

모든 malloc되지없이 동적 메모리와 귀하의 경우 문제 - 당신의 C 코드는 형식 불일치 오류가 될 것입니다! 마찬가지로 void명시 적 캐스트를 추가해야하므로 C의 모든 포인터가 작동합니다. 하지만 ... 왜 당신은 그것에게 일을 그런 식으로 ... 당신은 더 많은 기능을 C ++를 사용하는 길을 인도한다.

따라서 약간의 추가 작업이 가능할 수 있습니다. 그러나 더 큰 규모의 C ++ 채택을위한 관문 역할을 할 것입니다. 몇 년 동안 사람들은 1989 년에 기록 된 것처럼 그들이 당신의 교체로 보이는 기존 코드에 대해 불평 malloc에 전화를 new, 단지 대신 알고리즘을 호출하는 루프 기관의 코드 블록을 추출하고,하고자 안전하지 않은 가짜 다형성을 야단 치고 컴파일러가 그렇게 할 수 있다면 사소한 일이었습니다.

반면에 C로 작성하면 모두 동일하다는 것을 알고 있으므로 C ++ 대신 C로 작성하는 것이 잘못 되었습니까? 대답이 "아니오"인 경우 C ++에서 체리 피킹 기능사용하는 것도 잘못된 일이 아닙니다 .


2

많은 프로그래밍 언어는 하나 이상의 문화를 가지고 있으며, 언어가 무엇인지에 대한 특별한 아이디어를 가지고 있습니다. 시스템 프로그래밍에 적합한 저수준 언어를 갖는 것이 가능하고 실용적이며 유용하지만 C ++의 일부 기능을 사용하여 그러한 목적에 적합한 C의 방언을 보강하는 것이 가능하지만, 두 언어를 둘러싼 문화는 특히 그러한 합병을 선호하지 않습니다.

C ++의 일부 기능을 포함하는 임베디드 C 컴파일러에 대해 읽었습니다.

foo.someFunction(a,b,c);

본질적으로 해석

typeOfFoo_someFunction(foo, a, b, c);

정적 함수를 오버로드하는 기능뿐만 아니라 이름 변경 문제는 내보낼 때만 발생합니다.기능이 과부하되었습니다). C 컴파일러가 링크 및 런타임 환경에 대한 추가 요구 사항을 부과하지 않고 그러한 기능을 지원할 수있는 이유는 없지만 많은 C 컴파일러가 환경 부담을 피하기 위해 C ++에서 거의 모든 것에 대한 반사적 거부를 유발합니다. 그러한 비용을 부과하지 않는 기능조차 거부하십시오. 한편 C ++의 문화는 해당 언어의 모든 기능을 지원할 수없는 환경에 거의 관심이 없습니다. C의 문화가 그러한 기능을 수용하도록 변경되거나 가벼운 서브 세트의 구현을 장려하기 위해 C ++의 문화가 변경되지 않는 한, "하이브리드"코드는 두 언어의 많은 한계를 극복하면서 수확 능력이 제한되는 경향이 있습니다. 결합 된 수퍼 셋에서 운영 할 때의 이점.

플랫폼이 C와 C ++를 모두 지원하는 경우 C ++를 지원하는 데 필요한 추가 라이브러리 코드는 실행 파일을 다소 크게 만들지 만 그 효과는 그다지 크지 않습니다. C ++ 내에서 "C 기능"의 실행은 특별히 영향을받지 않을 것입니다. 더 큰 문제는 C 및 C ++ 옵티마이 저가 다양한 코너 경우를 처리하는 방법 일 수 있습니다. C에서 데이터 유형의 동작은 주로 저장된 비트의 내용에 의해 정의되며, C ++에는 의미가 주로 저장된 비트에 의해 정의되는 구조의 범주 (PODS--Plain Old Data Structures)가 있습니다. 그러나 C 및 C ++ 표준은 때때로 저장된 비트에 의해 암시되는 것과 반대되는 동작을 허용하며 "저장된 비트"동작에 대한 예외는 두 언어간에 다릅니다.


1
흥미로운 의견이지만 OP의 질문을 다루지 않습니다.
R Sahu

@RSahu : 언어를 둘러싼 "문화"에 맞는 코드는 그렇지 않은 코드보다 다양한 구현에 더 잘 지원되고 더 쉽게 적응할 수있는 경향이 있습니다. C와 C ++의 문화는 둘 다 OP가 제안하는 사용의 종류와 반대입니다. 구체적인 질문과 관련하여 좀 더 구체적인 사항을 추가하겠습니다.
supercat

1
C ++ 표준위원회에는 임베드 / 재무 / 게임 그룹이 있으며, 소멸한다고 주장하는 "작은 관심"상황을 정확하게 해결하는 것을 목표로합니다.
Yakk

@ Yakk : 저는 C ++에 관심이 많기 때문에 C ++ 세계를 깊게 따르지 않았다고 고백합니다. 나는 더 많은 방언에 대한 노력이 있었음을 알고 있지만, 그것이 실제로 어디에서나 얻을 것이라고 생각하지는 않았다.
supercat

2

고려해야 할 또 다른 중요한 요소는 코드를 상속받는 사람입니다.

그 사람은 항상 C 컴파일러를 가진 C 프로그래머가 되나요? 나는 그렇게 생각.

그 사람도 C ++ 컴파일러를 가진 C ++ 프로그래머입니까? 코드가 C ++ 관련 사항에 종속되도록하기 전에 이에 대해 합리적으로 확신하고 싶습니다.


2

다형성은 C ++이 무료로 제공하는 정말 좋은 기능입니다. 그러나 컴파일러를 선택할 때 고려해야 할 다른 측면이 있습니다. C에는 다형성에 대한 대안이 있지만 사용하면 눈썹이 약간 생길 수 있습니다. 가변성 함수Variadic function tutorial을 참조하십시오 .

귀하의 경우에는 다음과 같습니다

enum serialDataTypes
{
 INT =0,
 INT_P =1,
 ....
 }Arg_type_t;
....
....
void transmit(Arg_type_t serial_data_type, ...)
{
  va_list args;
  va_start(args, serial_data_type);

  switch(serial_data_type)
  {
    case INT: 
    //Send integer
    break;

    case INT_P:
    //Send data at integer pointer
    break;
    ...
   }
 va_end(args);
}

필립스의 접근 방식이 마음에 들지만 많은 통화로 라이브러리를 어지럽 힙니다. 위의 인터페이스는 깨끗합니다. 단점과 궁극적으로 선택의 문제가 있습니다.


Variadic 함수는 주로 인수의 수 유형이 가변적 인 사용 사례를 제공합니다 . 그렇지 않으면 필요하지 않으며 특히 특정 예에 비해 과도합니다. 받아들이는 일반적인 기능을 사용하는 것이 간단 할 것입니다 Arg_type_tvoid *데이터에 가리키는. 그렇기 때문에 (단일) 함수에 데이터 유형을 나타내는 인수를 제공하는 것이 실제로 가능한 대안입니다.
John Bollinger

1

몇 가지 다른 유형에 대해 "함수"를 정적으로 과부하시키는 특정한 경우에는 대신 _Generic매크로 기계 와 함께 C11을 사용하는 것이 좋습니다 . 나는 당신의 제한된 요구에 충분하다고 생각합니다.

Philip Kendall의 답변 을 사용하여 다음을 정의 할 수 있습니다.

#define transmit(X) _Generic((X),      \
   unsigned char*: transmit_uchar_buffer, \
   char*: transmit_char_buffer,           \
   unsigned char: transmit_uchar,         \
   char: transmit_char) ((X))

(위에 나열된 네 가지 유형 중에서) transmit(foo) 유형에 관계없이 코딩 하십시오 foo.

GCC (및 호환 가능한 Clang 컴파일러) 컴파일러 에만 관심이 있다면 확장 의 __builtin_types_compatible_p무게를 고려할 수 typeof있습니다.


1

함수 오버로드에만 C ++ 컴파일러를 사용하는 것은 나쁜 습관입니까?

IMHO의 견해, 예, 두 언어를 모두 좋아하기 때문에이 언어에 대답하려면 정신 분열증이되어야하지만, 효율성과는 관련이 없지만 언어의 안전과 관용적 표현과 비슷합니다.

C면

C 관점에서 함수 오버로드를 사용하기 위해 코드에 C ++이 필요하면 낭비가됩니다. C ++ 템플릿을 사용하여 정적 다형성에 사용하지 않는 한 완전히 다른 언어로 전환하는 대신 얻는 사소한 구문 설탕입니다. 또한 함수를 dylib로 내보내려면 (실제로 우려 할 수도 있고 아닐 수도 있음) 더 이상 모든 이름이 얽힌 기호를 사용하여 광범위하게 소비하기 위해 그렇게 할 수 없습니다.

C ++ 사이드

C ++ 관점에서 함수 오버로드와 함께 C와 같은 C ++을 사용해서는 안됩니다. 이것은 문체적인 독단성이 아니라 일상적인 C ++의 실제적인 사용과 관련된 것입니다.

C 유형의 시스템에 대해 작업하는 경우 C 유형의 시스템에 대해 작업하는 경우 일반적인 C 코드 코드는 합리적으로 제정되고 "안전"합니다 structs. C ++의 훨씬 더 풍부한 유형의 시스템에서 작업하고 나면 매일 가치가 memset있고 memcpy기능이되지 않는 일일 함수는 항상 기대어야합니다. 대신 C ++ 유형의 경우 복사 및 셔플 링 및 해제 할 원시 비트 및 바이트처럼 처리해서는 안되기 때문에 일반적으로 전염병처럼 피하고 싶은 함수입니다. 현재 코드 memset에서 프리미티브 및 POD UDT와 같은 것을 사용하더라도 누군가가 사용하는 UDT에 ctor를 추가하는 순간 (예 : 하나를 필요로하는 멤버 추가 만 포함)std::unique_ptr이러한 함수 또는 가상 함수 또는 이러한 종류의 항목에 대해 정의하면 모든 일반적인 C 스타일 코딩이 정의되지 않은 동작에 취약 해집니다. Herb Sutter 자신에게서 가져옵니다.

memcpymemcmp타입 시스템을 위반. 사용하여 memcpy객체를 복사하는 복사기를 사용하여 돈을 버는 것과 같다. 사용하여 memcmp객체를 비교하는 것은 자신의 명소를 계산하여 표범을 비교하는 것과 같다. 도구와 방법이 작업을 수행하는 것처럼 보일 수 있지만 너무 거칠어 수용 할 수 없습니다. C ++ 객체는 정보 숨기기에 관한 것입니다 (소프트웨어 엔지니어링에서 가장 수익성 높은 원칙; 항목 11 참조). 객체는 데이터를 숨기고 (항목 41 참조) 생성자와 할당 연산자를 통해 데이터를 복사하기위한 정확한 추상화를 고안합니다 (항목 52 ~ 55 참조) . 이를 통해 모든 것을 극복하는 것은 memcpy정보 숨기기를 심각하게 위반하는 것이며, 종종 메모리 및 리소스 누수 (최고), 충돌 (최악) 또는 정의되지 않은 동작 (최악)-C ++ 코딩 표준으로 이어집니다.

철학 은 C ++로 코드를 작성하는 경우 에만 적용 되므로 많은 C 개발자가 이에 동의하지 않고 올바르게 동의 합니다. C ++로 빌드되는 코드에서 항상 같은 함수를 사용하면 문제가 많은 코드를 작성하고 있을 가능성 높지만 C 에서 수행하면 문제가 없습니다 . 두 가지 언어는 유형 시스템의 차이로 인해 이와 관련하여 매우 다릅니다. 이 두 기능이 공통적으로 갖는 기능의 하위 집합을보고 싶은 유혹이 있으며 특히 C ++ 측면에서 다른 것과 같이 사용할 수 있다고 생각하지만 C + 코드 (또는 C-- 코드)는 일반적으로 C와 C보다 훨씬 더 문제가 많습니다. C ++ 코드.memcpy

마찬가지로 mallocC 스타일 컨텍스트 (EH를 의미하지 않음)에서 던질 수있는 C ++ 함수를 직접 호출 할 수 있다면 사용해서는 안됩니다. free메모리에 접근 하기 전에 C 스타일 코드 작성을 효과적으로 잡을 수없는 예외 . 당신이와 C로 ++ 빌드 파일있을 때마다 그래서 .cpp확장 또는 무엇이든을하고 같은 것들의 모든 유형을한다 malloc, memcpy, memset,qsort등으로, 기본 유형에서만 작동하는 클래스의 구현 세부 정보가 아닌 한, 아직 안전하지 않은 경우 예외 처리를 수행 해야하는 경우가 아니라면 아직 문제를 묻고 있습니다. 당신은 C ++ 코드를 작성하는 경우 대신 일반적으로 RAII에 의존와 같은 것들을 사용하려면 vector, unique_ptr, shared_ptr, 등, 그리고 가능하면 모든 일반 C 스타일의 코딩을 피하십시오.

C 및 x-ray 데이터 유형의 면도날을 사용하여 팀에서 부수적 피해를 입히지 않고 비트 및 바이트로 재생할 수있는 이유는 여전히 어떤 방법 으로든 자신을 해칠 수 있기 때문입니다. 유형 있지만 결코 할 수없는 일 때문에. 예외 처리와 함께 ctors, dtors 및 vtables와 같은 C ++ 기능을 포함하도록 C 유형 시스템을 확장하는 순간 모든 관용적 C 코드가 현재보다 훨씬 더 위험하게 렌더링되며 새로운 종류의 코드가 표시됩니다. C ++에서 볼 수 있듯이 완전히 다른 스타일의 코딩을 장려하는 철학과 사고 방식. 이제 RAII 준수 리소스와 달리 메모리를 관리하는 클래스에 대해 원시 포인터 과실을 사용하는 것을 고려합니다 unique_ptr. 그 사고 방식은 절대적인 안전 감각에서 벗어나지 않았습니다. 유형 시스템을 통해 허용 되는 것만으로 예외 처리와 같은 기능에 대해 C ++이 특히 안전 해야하는 것에서 진화했습니다 .

예외 안전

다시 말하지만, 당신이 C ++ 땅에있는 순간, 사람들은 여러분의 코드가 예외 안전하다고 기대할 것입니다. 사람들은 미래에 코드를 이미 C ++로 작성 및 컴파일 std::vector, dynamic_cast, unique_ptr, shared_ptr하고 코드에서 직접 또는 간접적으로 호출 된 코드에서 간단히 코드 를 사용 하여 코드가 이미 "추정 적으로"C ++이기 때문에 무해하지 않다고 생각할 때 코드를 유지 관리 할 수 ​​있습니다. 암호. 그 시점에서 우리는 일이 발생할 가능성에 직면해야하며, 다음과 같이 완벽하고 훌륭하고 멋진 C 코드를 취할 때 :

int some_func(int n, ...)
{
    int* x = calloc(n, sizeof(int));
    if (x)
    {
        f(n, x); // some function which, now being a C++ function, may 
                 // throw today or in the future.
        ...
        free(x);
        return success;
    }
    return fail;
}

... 이제 고장났습니다. 예외 안전을 위해 다시 작성해야합니다.

int some_func(int n, ...)
{
    int* x = calloc(n, sizeof(int));
    if (x)
    {
        try
        {
            f(n, x); // some function which, now being a C++ function, may 
                     // throw today or in the future (maybe someone used
                     // std::vector inside of it).
        }
        catch (...)
        {
            free(x);
            throw;
        }
        ...
        free(x);
        return success;
    }
    return fail;
}

심한! 그렇기 때문에 대부분의 C ++ 개발자는 이것을 대신 요구합니다.

void some_func(int n, ...)
{
    vector<int> x(n);
    f(x); // some function which, now being a C++ function, may throw today
          // or in the future.
}

위의 코드는 C ++ 개발자가 일반적으로 승인하는 RAII 준수 예외 안전 코드입니다 throw.

언어를 선택하십시오

RAII, 예외 안전, 템플릿, OOP 등을 사용하여 C ++의 유형 시스템과 철학을 채택하거나 원시 비트와 바이트를 중심으로 크게 변화하는 C를 채택해야합니다. 이 두 언어 사이에서 거룩하지 않은 결혼 관계를 형성해서는 안되며, 두 언어를 모호하게 만드는 대신 서로 다른 언어로 분리하여 다르게 취급해야합니다.

이 언어들은 당신과 결혼하기를 원합니다. 당신은 일반적으로 둘 다 데이트하고 장난하는 대신 하나를 선택해야합니다. 또는 당신은 나와 같은 일부 다처 주의자가되고 둘 다 결혼 할 수 있지만, 서로 시간을 보낼 때 생각을 완전히 바꾸고 서로 싸우지 않도록 서로 분리해야합니다.

이진 크기

호기심 때문에 방금 무료 목록 구현 및 벤치 마크를 취해 이것에 대해 궁금해 한 이후 C ++로 포팅하려고했습니다.

[...] C 컴파일러를 사용하지 않았기 때문에 C의 모양을 모릅니다.

... 이진 크기가 C ++로 빌드하는 것만으로 팽창하는지 알고 싶었습니다. 나는 어리석은 곳에서 명시 적 캐스트를 뿌려야했습니다 (C에서 할당 자 및 데이터 구조와 같은 저수준 항목을 실제로 작성하는 것을 좋아하는 이유 중 하나).

, C로를 구축하고 말 사용과 단지 차이 - 이것은 단순한 콘솔 응용 프로그램과 ++ 기능, 심지어 연산자 오버로딩을 어떤 C를 사용하지 않은 코드와 함께 MSVC 64 비트 릴리스 빌드를 비교 한 <cstdlib>대신 <stdlib.h>과 그런 것들이지만 바이너리 크기와 전혀 차이가 없다는 사실에 놀랐습니다!

바이너리는 9,728C로 빌드 9,278될 때 바이트 였으며 마찬가지로 C ++ 코드로 컴파일 될 때 바이트였습니다. 나는 실제로 그것을 기대하지 않았다. 나는 EH와 같은 것들이 적어도 거기에 조금 더 추가 될 것이라고 생각했지만 (적어도 100 바이트와 다를 것이라고 생각했지만) 아마도 내가 EH 관련 지침을 추가 할 필요가 없다는 것을 알 수 있었을 것입니다. C 표준 라이브러리를 사용하면 아무것도 던지지 않습니다. 나는 무언가를 생각 했다RTTI와 같이 이진 크기에 약간을 추가합니다. 여하튼, 그것을 보는 것은 약간 시원했다. 물론이 결과에서 일반화해야한다고 생각하지는 않지만 적어도 나에게 깊은 인상을주었습니다. 또한 벤치 마크에 영향을 미치지 않았으며 결과적으로 동일한 결과 바이너리 크기도 동일한 결과 기계 명령을 의미한다고 생각하기 때문에 자연스럽게 그렇게합니다.

즉, 위에서 언급 한 안전 및 엔지니어링 문제로 이진 크기를 걱정하는 사람은 누구입니까? 다시 한 번 말하지만, 언어를 선택하지 말고 철학을 받아들이십시오. 그것이 제가 추천하는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.