임베디드 시스템에서 유형 추상화를 언제 사용해야 합니까?

StackOverflow https://stackoverflow.com/questions/7084

  •  08-06-2019
  •  | 
  •  

문제

저는 다양한 임베디드 시스템에 대해 작업해왔습니다.그들은 모두 사용했습니다 typedefs (또는 #defines) 다음과 같은 유형의 경우 UINT32.

이는 프로그래머에게 유형의 크기를 알려주고 오버플로 등의 가능성을 더 잘 인식하게 하므로 좋은 기술입니다.

그러나 일부 시스템에서는 프로젝트 수명 동안 컴파일러와 프로세서가 변경되지 않는다는 것을 알고 있습니다.

그렇다면 프로젝트별 유형을 생성하고 시행하기로 한 결정에 무엇이 영향을 미칩니까?

편집 나는 내 질문의 요점을 잃을 수 있다고 생각했고 아마도 두 가지 일 것입니다.

임베디드 프로그래밍을 사용하면 인터페이스에 특정 크기 유형이 필요할 수 있으며 RAM과 같은 제한된 리소스에 대처해야 할 수도 있습니다.이는 피할 수 없지만 컴파일러의 기본 유형을 사용하도록 선택할 수 있습니다.

다른 모든 것에서는 유형의 중요성이 덜합니다.
오버플로가 발생하지 않도록 주의해야 하며 레지스터 및 스택 사용에 주의해야 할 수도 있습니다.이로 인해 UINT16, UCHAR.다음과 같은 유형을 사용하여 UCHAR 그러나 컴파일러 'fluff'를 추가할 수 있습니다.일반적으로 레지스터가 더 크기 때문에 일부 컴파일러에서는 결과를 해당 형식으로 강제 변환하는 코드를 추가할 수 있습니다.

i++;
될 수 있다
ADD REG,1
AND REG, 0xFF
그것은 불필요합니다.

그래서 내 질문은 다음과 같아야 한다고 생각합니다.

임베디드 소프트웨어의 제약을 고려할 때 많은 사람이 작업하는 프로젝트에 대해 설정하는 최선의 정책은 무엇입니까? 모든 사람이 동일한 수준의 경험을 갖고 있지는 않습니다.

도움이 되었습니까?

해결책

나는 유형 추상화를 거의 사용하지 않습니다.다음은 주관성의 오름차순으로 정렬된 내 주장입니다.

  1. 지역 변수는 레지스터에 맞추기를 원한다는 점에서 구조체 멤버 및 배열과 다릅니다.32b/64b 타겟에서는 로컬 int16_t 컴파일러는 의미 체계에 따라 /force/overflow에 작업을 추가해야 하므로 로컬 int에 비해 코드 속도가 느려질 수 있습니다. int16_t.C99는 intfast_t typedef, AFAIK 일반 int는 레지스터에도 적합하며 이름이 더 짧습니다.

  2. 이러한 typedef를 좋아하는 조직은 거의 변함없이 그 중 여러 개를 갖게 됩니다(INT32, int32_t, INT32_T, 무한대).따라서 내장 유형을 사용하는 조직은 한 가지 이름 세트만 갖는 것이 어떤 면에서는 더 좋습니다.사람들이 stdint.h나 windows.h 또는 기존의 모든 형식 정의를 사용했으면 좋겠습니다.타겟에 해당 .h 파일이 없으면 파일을 추가하는 것이 얼마나 어렵습니까?

  3. typedef는 이론적으로 이식성에 도움이 될 수 있지만, 저는 그로부터 아무것도 얻지 못했습니다.32b 대상에서 16b 대상으로 포팅할 수 있는 유용한 시스템이 있습니까?32b 대상으로 포팅하는 것이 쉽지 않은 16b 시스템이 있습니까?더욱이 대부분의 변수가 정수인 경우 실제로 새 대상의 32비트에서 뭔가를 얻을 수 있습니다. int16_t, 그렇지 않을 것입니다.그리고 이식하기 어려운 장소는 어쨌든 수동 검사가 필요한 경향이 있습니다.포트를 시도하기 전에는 포트가 어디에 있는지 알 수 없습니다.이제 누군가가 여기저기에 typedef가 있으면 이식하는 것이 너무 쉽다고 생각한다면 소수의 시스템에서 발생하는 이식 시간이 오면 코드 베이스의 모든 이름을 변환하는 스크립트를 작성하십시오.이는 "수동 검사가 필요하지 않음" 논리에 따라 작동해야 하며 실제로 이점을 제공하는 시점까지 노력을 연기합니다.

  4. 이제 이식성이 typedef의 이론적 이점일 수 있다면, 가독성 확실히 하수구로 내려갑니다.stdint.h를 살펴보세요: {int,uint}{max,fast,least}{8,16,32,64}_t.종류가 많습니다.프로그램에는 많은 변수가 있습니다.무엇이 필요한지 정말 이해하기 쉽나요? int_fast16_t 그리고 어느 것이 필요합니까? uint_least32_t?우리는 그들 사이를 몇 번이나 조용히 전환하여 완전히 무의미하게 만들고 있습니까?(저는 특히 BOOL/Bool/eBool/boolean/bool/int 변환을 좋아합니다.형식 정의를 요구하는 질서 있는 조직에서 작성한 모든 프로그램에는 형식 정의가 포함되어 있습니다.

  5. 물론 C++에서는 오버로드된 연산자와 항목으로 템플릿 클래스 인스턴스화의 숫자를 래핑하여 유형 시스템을 더 엄격하게 만들 수 있습니다.즉, 이제 "class Number<int,Least,32>에는 class Number<unsigned long long,Fast,64> 유형의 인수에 대한 연산자+ 오버로드가 없습니다. 후보는..." 형식의 오류 메시지가 표시됩니다. 이것을 "가독성"이라고 부르지도 마세요.이러한 래퍼 클래스를 올바르게 구현할 가능성은 미미하며 대부분의 경우 수많은 템플릿 인스턴스화가 컴파일될 때까지 기다립니다.

다른 팁

C99 표준에는 다양한 표준 크기 정수 유형이 있습니다.C99(gcc 지원)를 지원하는 컴파일러를 사용할 수 있다면 다음에서 찾을 수 있습니다. <stdint.h> 프로젝트에서 사용할 수 있습니다.

또한 임베디드 프로젝트에서는 유형을 단위 변환과 같은 일종의 "안전망"으로 사용하는 것이 특히 중요할 수 있습니다.C++를 사용할 수 있다면 기본 스칼라 유형에 대한 연산으로 컴파일되는 C++ 유형 시스템(템플릿을 통해)에 의해 정의된 물리적 단위에서 작업할 수 있는 "단위" 라이브러리가 있다는 것을 알고 있습니다.예를 들어, 이러한 라이브러리에서는 distance_t 에게 mass_t 단위가 정렬되지 않기 때문입니다.실제로 컴파일러 오류가 발생합니다.

C++나 그런 식으로 코드를 작성할 수 있는 다른 언어로 작업할 수 없더라도 최소한 C 유형 시스템을 사용하면 이와 같은 오류를 눈으로 확인할 수 있습니다.(실제로는 Simonyi의 헝가리어 표기법의 원래 의도였습니다.) 단지 컴파일러가 다음을 추가한다고 소리지르지 않을 것이기 때문입니다. meter_t 에게 gram_t 그런 유형을 사용해서는 안된다는 의미는 아닙니다.그러면 코드 검토가 단위 오류를 발견하는 데 훨씬 더 생산적이 될 것입니다.

내 의견은 최소/최대/특정 크기에 의존하는 경우입니다. ~하지 않다 그냥 (말하자면) unsigned int 32바이트입니다 - 사용 uint32_t 대신 (컴파일러가 C99를 지원한다고 가정).

저는 시스템 API를 정의하기 위해 stdint.h 유형을 사용하는 것을 좋아합니다. 왜냐하면 항목의 크기가 얼마나 큰지 명시적으로 알려주기 때문입니다.Palm OS의 옛날에는 시스템 API가 매우 고전적인 Mac OS에서 상속된 "Word" 및 "SWord"와 같은 촌스러운 유형을 사용하여 정의되었습니다.그들은 대신 Int16이라고 말하도록 정리했으며 특히 해당 시스템의 이상한 16비트 포인터 문제와 관련하여 초보자가 API를 더 쉽게 이해할 수 있게 만들었습니다.Palm OS Cobalt를 설계할 때 stdint.h의 이름과 일치하도록 해당 이름을 다시 변경하여 더욱 명확하게 만들고 관리해야 하는 typedef의 양을 줄였습니다.

나는 MISRA 표준이 typedef의 사용을 제안(요구?)한다고 믿습니다.

개인적인 관점에서 typedef를 사용하면 특정 유형의 크기(비트/바이트)에 대한 혼동이 없습니다.나는 수석 개발자가 표준 유형을 사용하여 두 가지 개발 방법을 모두 시도하는 것을 보았습니다.int 및 사용자 정의 유형 사용(예:UINT32.

코드가 이식성이 없으면 거의 없습니다. 진짜 typedef를 사용하면 이점이 있습니다. 하지만 , 저처럼 두 가지 유형의 소프트웨어(휴대용 및 고정 환경)에서 작업한다면 표준을 유지하고 맞춤형 유형을 사용하는 것이 유용할 수 있습니다.최소한 당신이 말한 것처럼 프로그래머는 자신이 얼마나 많은 메모리를 사용하고 있는지 잘 알고 있습니다.고려해야 할 또 다른 요소는 코드가 다른 환경으로 이식되지 않을 것이라고 얼마나 '확신'하는가입니다.하드웨어 엔지니어가 갑자기 보드를 변경해야 했기 때문에 프로세서 특정 코드를 번역해야 하는 것을 본 적이 있습니다. 이는 좋은 상황은 아니지만 사용자 정의 typedef로 인해 훨씬 ​​더 나쁠 수 있었습니다!

일관성, 편의성 및 가독성."UINT32"는 일부 시스템에 해당하는 "unsigned long long"보다 훨씬 읽기 쉽고 쓰기 쉽습니다.

또한 컴파일러와 프로세서는 프로젝트 수명 동안 고정될 수 있지만 해당 프로젝트의 코드는 다른 프로젝트에서 새로운 생명을 찾을 수 있습니다.이 경우 일관된 데이터 유형을 갖는 것이 매우 편리합니다.

귀하의 임베디드 시스템이 어떻게든 안전이 중요한 시스템 (또는 유사), 그것은 강력하다 조언하다 (필요하지 않은 경우) 일반 유형보다 typedef를 사용합니다.

처럼 TK. 전에도 말했지만, 미스라-C 그렇게 하기 위한 (권고) 규칙이 있습니다:

규칙 6.3(권고): 기본 숫자 유형 대신 크기와 부호를 나타내는 유형 정의를 사용해야 합니다.

(MISRA-C 2004에서;MISRA-C 1998의 규칙 #13(adv)입니다.


이 영역에서는 C++에도 동일하게 적용됩니다.예. JSF C++ 코딩 표준:

AV 규칙 209 개발자가 사용할 수있는 모든 Sta Ndard 유형을 정의하기 위해 UniversaltyPes 파일이 작성됩니다.유형은 다음과 같습니다.[uint16, int16, uint32_t 등]

사용 <stdint.h> PC에서 단위 테스트를 위해 코드의 이식성이 향상됩니다.

모든 것을 테스트할 때 꽤 힘들 수 있지만 대상 시스템에서는 여전히 문제가 발생합니다. int 갑자기 길이가 16비트에 불과해졌습니다.

제가 이상할 수도 있지만 정수 유형으로 ub, ui, ul, sb, si 및 sl을 사용합니다.아마도 16비트의 "i"는 약간 오래된 것 같지만 uw/sw보다 ui/si의 모양이 더 좋습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top