2020년 5월 26일 화요일

Doxygen 사용법

1. 기본적인 주석 형태
/**
* 기본적인 주석 형태
*/

2. 메인 페이지의 주석 
/**
* @mainpage 메인페이지의 제목을 적는다.
* @brief 간단한 설명
* @details 자세한 설명
* @section intro 소개
* @section Program 프로그램명
* @section INOUTPUT 입출력자료
* @section CREATEINFO 작성정보
* @section MODIFYINFO 수정 정보
*/

3. 각 파일에 들어갈 주석
/**
* @file hello.c
* @brief 간단한 설명
* @detail 자세한 설명
* @date 2018/1/30
*/

4. 각 함수에 대한 주석
/**
* @brief 어떤 기능을 하는 함수
* @param value 연산에 필요한 변수
* @return value 연산 결과를 반환
*/ 

5. 코드 삽입시 
@code
여기에 코드가 들어가면 된다.
@endcode

6. 버그 및 해야할 일 기록
@todo 언제까지 해야할일
@bug 값의 범위를 넘을경우 발생되는 버그가 있을 수 있다.

7. struct(class), enum
 /**  @brief buffer structor   Telnet에서 정송되는 데이터에 대해 프로토콜을 처리해야 하기 위하여,  효율적으로 데이터를 전송해야 할 입출력 버퍼 structor */ 
struct buffer{
  char *buf;   /**< 데이터를 저장할 주소공간   */         
  int size;   /**< buf에 할당된 메모리 크기   */         
  int head;   /**< buf에 저장된 데이터의 처음 Index   */
  int tail;   /**< buf에 저장된 데이터의 마지막 index */
  int count;  /**< buf에 저장된 데이터의 byte 수      */ 
}; 
 /** @brief TRUE FALSE정의. */ 
enum BOOLEAN { FALSE=0/**< FALSE */    TRUE /**< TRUE */ };

8. define, 전역 변수
#define MAX_READ_BUF   1024    /**< 최대 read buffer size      */
 short  port;                   /**< Telnet port number */ 


2020년 5월 16일 토요일

이클릅스 깃 연동

1. git서버에  폴더를 생성하고 git 초기화 해준다.
    $git init  --bare --shared

2. eclipse에서 oop C++프로젝트를 생성한다.


3. eclipse 메뉴창에서 창 -> Perspective -> Perspective 열기 -> 기타 를 선택하고, Git선택 후 열기


4. Clone a Git repository 를 선택하면 git저장소 복제 화면이 나오고 아래와 같이 설정한뒤 다음을 클릭한다.


5. Branch Selection에서 master로 체크되어있으면 다음을 클릭한다. 프로젝트의 내용이 비어있을 경우 master가 표시 되지 않을수도 있다.

6.  Local Destination의 내용은 다음과 같다.
대상 디렉토리는 이클립스에서 git서버와 연동될 폴더 지정이다.

7. 다시 C++프로젝트 퍼스펙티브로 이동하여 oop프로젝트 에서 우측 클릭을 하면 팀이 나오고 팀에서 프로젝트 공유를 선택하여 아래와 같이 설정하고 완료 한다.
Repository에서 방금 생성한 git서버를 선택


2020년 4월 25일 토요일

GOOGLE TEST MANUAL (Primer)

ㄹGoogletest Primer

소개 : 왜 구글테스트인가?

구글테스트는 더 나은 C++테스트를 작성하는데 도움이 됩니다.
googletest는 Google의 특정 요구 사항과 제약 사항을 염두에두고 테스팅 기술 팀에서 개발 한 테스트 프레임 워크입니다. Linux, Windows, Mac 어디서든 C++ 코드를 작성하면 googletest가 도움이 될 수 있습니다. 또한 단위 테스트뿐만 아니라 모든 종류의 테스트를 지원합니다.


명명법에 주의 하라.

참고 : Test, Test Case 및 Test Suite라는 용어를 다르게 정의하면 약간의 혼동이있을 수 있으므로이를 오해하지 마십시오.

역사적으로 googletest는 관련 테스트를 그룹화하기 위해 테스트 케이스라는 용어를 사용하기 시작했지만 ISTQB (International Software Testing Qualifications Board) 자료 및 소프트웨어 품질에 대한 다양한 교재를 포함하여 현재 발행물은 이를 위해 Test Suite라는 용어를 사용합니다.

googletest에서 사용되는 테스트라는 용어는 ISTQB 및 기타 Test Case라는 용어에 해당합니다.

Test라는 용어는 ISTQB의 Test Case 정의를 포함하여 일반적으로 충분히 의미가 있으므로 여기서 큰 문제는 아닙니다. 그러나 Google 테스트에 사용 된 Test Cse라는 용어는 모순되는 의미이므로 혼동됩니다.

googletest는 최근 Test Case라는 용어를 Test Suite로 대체하기 시작했습니다. 선호하는 API는 TestSuite입니다. 이전 TestCase API는 천천히 사용이 중단되고 리팩터링됩니다

따라서 용어에 대한 다른 정의에 유의하십시오.

Assertions

googletest의 assertions은 함수 호출과 유사한 매크로입니다. 동작에 대해 assertions을 작성하여 클래스 또는 함수를 테스트합니다. assertions이 실패하면 googletest는 assertions의 소스 파일과 줄 번호 위치를 실패 메시지와 함께 인쇄합니다. googletest의 메시지에 추가 될 맞춤 실패 메시지를 제공 할 수도 있습니다.

assertions은 쌍을 이루어 동일한 것을 테스트하지만 현재 기능에 다른 영향을 미칩니다. 따라서
ASSERT_*은 실패하면 치명적 실패를 생성하고 현재 기능을 중단합니다.
EXPECT_*은 치명적이지 않은 오류를 생성하여 현재 기능을 중단시키지 않습니다. 일반적으로 EXPECT_* 는 테스트에서 둘 이상의 실패를보고 할 수 있으므로 선호됩니다. 그러나 해당 assertions이 실패 할 때 계속하는 것이 타당하지 않은 경우 ASSERT_ *를 사용해야합니다.

실패한 ASSERT_*는 현재 함수에서 즉시 리턴하므로 그 뒤에 오는 clean-up코드를 건너 뛸 수 있으므로 space leak(or memory leak)이 발생할 수 있습니다. 누출의 특성에 따라 수정해야 할 수도 있고 그렇지 않을 수도 있습니다. 따라서 어설 션 오류 외에 힙 검사기 오류가 발생하면이 점을 명심하십시오.

사용자 정의 실패 메시지를 제공하려면 << 연산자를 사용하여 매크로에 간단히 메시지를 스트리밍하십시오. 예를 들면 :
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";

for (int i = 0; i &lt; x.size(); ++i) {
  EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " &lt;&lt; i;
}

Basic Assertions

이러한 assertions은 참/거짓 조건 테스트를 수행합니다.
Fatal assertionNonfatal assertionVerifies
ASSERT_TRUE(condition);EXPECT_TRUE(condition);condition is true
ASSERT_FALSE(condition);EXPECT_FALSE(condition);condition is false
실패하면 ASSERT_ *는 치명적 실패를 생성하고 현재 함수에서 리턴하며 EXPECT_ *는 치명적이지 않은 실패를 생성하여 함수를 계속 실행할 수 있습니다. 두 경우 모두 assertions 오류는 테스트에 실패했음을 의미합니다.

Binary Comparison

이 섹션에서는 두 값을 비교하는 assertions에 대해 설명합니다.
Fatal assertionNonfatal assertionVerifies
ASSERT_EQ(val1, val2);EXPECT_EQ(val1, val2);val1 == val2
ASSERT_NE(val1, val2);EXPECT_NE(val1, val2);val1 != val2
ASSERT_LT(val1, val2);EXPECT_LT(val1, val2);val1 &lt; val2
ASSERT_LE(val1, val2);EXPECT_LE(val1, val2);val1 &lt;= val2
ASSERT_GT(val1, val2);EXPECT_GT(val1, val2);val1 &gt; val2
ASSERT_GE(val1, val2);EXPECT_GE(val1, val2);val1 &gt;= val2
값 인수(val1, val2)는 assertions의 비교 연산자와 비교할 수 있어야합니다. 그렇지 않으면 컴파일러 오류가 발생합니다.  <<가 지원되면 어설 션이 실패 할 때 인수를 인쇄하기 위해 호출됩니다. 그렇지 않으면 googletest는 최선의 방법으로 인쇄하려고 시도합니다. 자세한 내용과 인수 인쇄를 사용자 정의하는 방법은 설명서를 참조하십시오.

이러한 assertions은 사용자 정의 형식에서 작동하지만 해당 비교 연산자 (예 : == 또는 <)를 정의한 경우에만 작동합니다. Google C++ 스타일 가이드에서는 권장하지 않으므로 ASSERT_TRUE() 또는 EXPECT_TRUE()를 사용하여 사용자 정의 유형의 두 객체가 동일한 지 확인해야합니다.
그러나 ASSERT_EQ (실제, 예상)가 ASSERT_TRUE (실제 == 예상)보다 선호됩니다. 실패시 실제 및 예상 값을 알려줍니다.

인수는 항상 정확히 한 번만 평가됩니다. 따라서 인수에 side effects를 가진것도 좋습니다. 그러나 일반적인 C/C++ 함수와 마찬가지로 인수의 평가 순서는 정의되어 있지 않으며 (즉, 컴파일러는 순서를 자유롭게 선택할 수 있습니다) 코드는 특정 인수 평가 순서에 의존해서는 안됩니다.

ASSERT_EQ()는 포인터에서 포인터 동등성을 수행합니다. 두 개의 C 문자열에서 사용되는 경우 동일한 값이 아닌 동일한 메모리 위치에 있는지 테스트합니다. 따라서 C 문자열 (예 : const char *)을 값으로 비교하려면 나중에 설명 할 ASSERT_STREQ()를 사용하십시오. 특히 C 문자열이 NULL임을 확인하려면 ASSERT_STREQ(c_string, NULL)를 사용하십시오. c ++ 11이 지원되는 경우 ASSERT_EQ(c_string, nullptr)를 사용하십시오. 두 개의 문자열 객체를 비교하려면 ASSERT_EQ를 사용해야합니다.

포인터 비교를 수행 할 때 *_EQ(ptr, NULL) 및 *_NE(ptr, NULL) 대신 *_EQ(ptr, nullptr) 및 *_NE(ptr, nullptr)을 사용하십시오.자세한 내용은 FAQ를 참조하십시오.

부동 소수점 숫자로 작업하는 경우 반올림으로 인한 문제를 피하기 위해 이러한 매크로 중 일부의 부동 소수점 변형을 사용할 수 있습니다. 자세한 내용은 고급 googletest 주제를 참조하십시오.

String Comparison

이 그룹의 assertions은 두 개의 C문자열을 비교합니다. 두 개의 문자열 객체를 비교하려면 EXPECT_EQ, EXPECT_NE 등을 대신 사용하십시오.
Fatal assertionNonfatal assertionVerifies
ASSERT_STREQ(str1,str2);EXPECT_STREQ(str1,str2);두 문자열의 내용이 동일합니다
ASSERT_STRNE(str1,str2);EXPECT_STRNE(str1,str2);두 문자열의 내용이 다릅니다
ASSERT_STRCASEEQ(str1,str2);EXPECT_STRCASEEQ(str1,str2);두 문자열은 대/소 문자를 무시하고 내용이 동일합니다.
ASSERT_STRCASENE(str1,str2);EXPECT_STRCASENE(str1,str2);두 문자열은 대소 문자를 무시하고 내용이 다릅니다.

Simple Tests

테스트를 만들려면

1. 테스트 함수를 정의하고 이름을 지정하려면 TEST() 매크로를 사용하십시오. 이들은 값을 반환하지 않는 일반적인 C++ 함수입니다.
2. 이 함수에서 포함하려는 유효한 C++ 문과 함께 다양한 googletest 어설 션을 사용하여 값을 확인하십시오.
3. 테스트 결과는 assertions에 의해 결정됩니다. 테스트에서 어설 션이 치명적이거나 치명적이지 않은 경우 또는 테스트가 중단되면 전체 테스트가 실패합니다. 그렇지 않으면 성공합니다.
TEST(TestSuiteName, TestName) {
  ... test body ...
}
TEST() 인수는 일반에서 구체적으로 진행됩니다. 첫 번째 인수는 test suite의 이름이고 두 번째 인수는 test suite내의 테스트 이름입니다. 두 이름 모두 유효한 C++ 식별자 여야하며 밑줄 (_)을 포함해서는 안됩니다. 테스트의 전체 이름은 포함된 test suite와 개별 이름으로 구성됩니다. 다른 테스트 test suite의 테스트는 동일한 개별 이름을 가질 수 있습니다.

예를 들어 간단한 정수 함수를 보자.
int Factorial(int n);  // Returns the factorial of n
이 함수의 test suite는 다음과 같습니다.
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
  EXPECT_EQ(Factorial(0), 1);
}

// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
  EXPECT_EQ(Factorial(1), 1);
  EXPECT_EQ(Factorial(2), 2);
  EXPECT_EQ(Factorial(3), 6);
  EXPECT_EQ(Factorial(8), 40320);
}
googletest는 테스트 결과를 test suite별로 그룹화하므로 논리적으로 관련된 테스트는 동일한 test suite에 있어야합니다. 다시 말해, TEST()에 대한 첫 번째 인수는 동일해야합니다. 위의 예에서, 동일한 test suite인 FactorialTest에 속하는 두 개의 테스트 (HandlesZeroInput 및 HandlesPositiveInput)가 있습니다.

테스트 test suite이름을 지정할 때는 함수 및 클래스 이름 지정과 동일한 규칙을 따라야합니다.

Test Fixtures: Using the Same Data Configuration for Multiple Tests {#same-data-multiple-tests}

비슷한 데이터에서 작동하는 둘 이상의 테스트를 작성하는 경우 테스트 픽스처를 사용할 수 있습니다. 이를 통해 여러 가지 다른 테스트에 동일한 구성의 객체를 재사용 할 수 있습니다.

fixture을 만들려면 :

1. :: testing :: Test에서 클래스를 파생시킵니다. 서브 클래스에서 fixture 멤버에 접근하고 싶기 때문에 protected :로 본문을 시작하십시오.
2. 클래스 내에서 사용할 객체를 선언하십시오.
3. 필요한 경우 기본 생성자 또는 SetUp() 함수를 작성하여 각 테스트에 대한 개체를 준비하십시오. 일반적인 실수는 C++ 11에서 대문자 U를 소문자 u로 재정의 하여 SetUp()을 Setup()으로 사용하는 것 입니다. 철자가 올바른지 확인하세요. 
4. 필요한 경우, 소멸자 또는 TearDown() 함수를 작성하여 SetUp()에 할당 한 모든 리소스를 해제하십시오. 생성자/소멸자를 사용해야 할 때와 SetUp()/TearDown()을 사용해야 할 때를 알려면 FAQ를 읽으십시오.
5. 필요한 경우 테스트에서 공유 할 서브 루틴을 정의하십시오.
TEST_F(TestFixtureName, TestName) {
  ... test body ...
}
TEST()와 마찬가지로 첫 번째 인수는 test suite이름이지만 TEST_F()의 경우 test fixture클래스의 이름이어야합니다. 당신은 아마 추측했을 것입니다 : _F는 Fixture입니다.

불행히도 C++ 매크로 시스템은 두 가지 유형의 테스트를 모두 처리 할 수있는 단일 매크로를 만들 수 없습니다. 잘못된 매크로를 사용하면 컴파일러 오류가 발생합니다.

또한 test fixture클래스를 TEST_F()에서 사용하기 전에 먼저 정의해야합니다. 그렇지 않으면 컴파일러 오류 "virtual outside class declaration"이 발생합니다.

TEST_F()로 정의 된 각 테스트에 대해 googletest는 런타임시 새로운 테스트 설비를 생성하고 즉시 SetUp()을 통해 초기화하고 테스트를 실행 한 다음 TearDown()을 호출하여 정리 한 다음 테스트 설비를 삭제합니다. 동일한 test suite의 테스트마다 test fixture객체가 다르므로 googletest는 다음 test fixture를 작성하기 전에 항상 test fixture를 삭제합니다. googletest는 여러 테스트에 동일한 test fixture를 재사용하지 않습니다. 한 번의 테스트로 texture를 변경해도 다른 테스트에는 영향을 미치지 않습니다.

예를 들어, 다음 인터페이스가있는 Queue라는 FIFO 대기열 클래스에 대한 테스트를 작성해 보겠습니다.
template <typename E>  // E is the element type.
class Queue {
 public:
  Queue();
  void Enqueue(const E& element);
  E* Dequeue();  // Returns NULL if the queue is empty.
  size_t size() const;
  ...
};
먼저 fixture클래스를 정의하십시오. 규칙에 따라 FooTest라는 이름을 지정해야합니다. 여기서 Foo는 테스트중인 클래스입니다.
class QueueTest : public ::testing::Test {
 protected:
  void SetUp() override {
     q1_.Enqueue(1);
     q2_.Enqueue(2);
     q2_.Enqueue(3);
  }

  // void TearDown() override {}

  Queue<int> q0_;
  Queue<int> q1_;
  Queue<int> q2_;
};
이 경우 소멸자가 이미 수행 한 것 이외의 각 테스트 후에 정리할 필요가 없으므로 TearDown()이 필요하지 않습니다.

이제 TEST_F ()와이 조명기를 사용하여 테스트를 작성합니다.
TEST_F(QueueTest, IsEmptyInitially) {
  EXPECT_EQ(q0_.size(), 0);
}

TEST_F(QueueTest, DequeueWorks) {
  int* n = q0_.Dequeue();
  EXPECT_EQ(n, nullptr);

  n = q1_.Dequeue();
  ASSERT_NE(n, nullptr);
  EXPECT_EQ(*n, 1);
  EXPECT_EQ(q1_.size(), 0);
  delete n;

  n = q2_.Dequeue();
  ASSERT_NE(n, nullptr);
  EXPECT_EQ(*n, 2);
  EXPECT_EQ(q2_.size(), 1);
  delete n;
}
위의 ASSERT_* 및 EXPECT_* 어설 션을 모두 사용합니다. 경험적으로 어설 션 오류 후에 테스트에서 더 많은 오류를 계속 나타내려면 EXPECT_*를 사용하고 실패 후 계속할 때는 ASSERT_*를 사용하는 것이 좋습니다. 예를 들어, Dequeue 테스트에서 두 번째 어설 션은 ASSERT_NE(nullptr, n)입니다. 나중에 포인터 n을 역 참조해야하므로 n이 NULL 일 때 segfault가 발생합니다.

이러한 테스트가 실행되면 다음이 발생합니다.
1. googletest는 QueueTest 객체를 생성합니다 (t1이라고 함).
2. t1.SetUp ()은 t1을 초기화합니다.
3. 첫 번째 테스트 (IsEmptyInitially)는 t1에서 실행됩니다.
4. 테스트가 완료된 후 t1.TearDown ()이 정리됩니다.
5. t1이 파괴되었습니다.
6. 위의 단계는 다른 QueueTest 객체에서 반복되며 이번에는 DequeueWorks 테스트를 실행합니다.

테스트 호출

TEST() 및 TEST_F()는 테스트를 googletest에 암시 적으로 등록합니다. 따라서 다른 많은 C++ 테스트 프레임 워크와 달리 정의 된 테스트를 모두 실행하기 위해 다시 나열 할 필요는 없습니다.

테스트를 정의한 후 RUN_ALL_TESTS()로 테스트를 실행할 수 있습니다. 모든 테스트가 성공하면 0을, 그렇지 않으면 1을 리턴합니다. RUN_ALL_TESTS ()는 링크 단위에서 모든 테스트를 실행합니다. 테스트 단위 나 소스 파일이 다를 수 있습니다.

호출되면 RUN_ALL_TESTS()매크로는 다음과 같습니다.

  • 모든 googletest 플래그의 상태를 저장합니다.
  • 첫 번째 테스트에 대한 테스트 픽스처 객체를 만듭니다.
  • SetUp ()을 통해 초기화합니다.
  • fixture 객체에서 테스트를 실행합니다.
  • TearDown ()을 통해 조명기를 정리합니다.
  • fixture를 삭제합니다.
  • 모든 googletest 플래그의 상태를 복원합니다.
  • 모든 테스트가 실행될 때까지 다음 테스트에 대해 위 단계를 반복합니다.
치명적인 오류가 발생하면 후속 단계를 건너 뜁니다.
중요 : RUN_ALL_TESTS()의 반환 값을 무시해서는 안됩니다. 그렇지 않으면 컴파일러 오류가 발생합니다. 이 설계의 근거는 자동화 된 테스트 서비스가 stdout/stderr 출력이 아니라 종료 코드를 기반으로 테스트가 통과했는지 여부를 결정한다는 것입니다. 따라서 main() 함수는 RUN_ALL_TESTS()의 값을 반환해야합니다.

또한 RUN_ALL_TESTS()를 한 번만 호출해야합니다. 그것을 두 번 이상 호출하면 일부 고급 Google 테스트 기능 (예 : 스레드 안전 사망 테스트)과 충돌하므로 지원되지 않습니다.

Writing the main() Function

대부분의 사용자는 고유한 기본 기능을 작성할 필요가 없으며 대신 적절한 진입 점을 정의하는 gtest_main(gtest와 반대로)과 연결해야합니다. 자세한 내용은이 섹션의 끝 부분을 참조하십시오. 이 섹션의 나머지 부분은 테스트를 실행하기 전에 fixture 및test suites의 프레임 워크 내에서 표현할 수없는 사용자 정의 작업을 수행해야하는 경우에만 적용해야합니다.

자체 main() 함수를 작성하면 RUN_ALL_TESTS() 값을 리턴해야합니다.

이 상용구에서 시작할 수 있습니다 :
#include "this/package/foo.h"

#include "gtest/gtest.h"

namespace my {
namespace project {
namespace {

// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
 protected:
  // You can remove any or all of the following functions if their bodies would
  // be empty.

  FooTest() {
     // You can do set-up work for each test here.
  }

  ~FooTest() override {
     // You can do clean-up work that doesn't throw exceptions here.
  }

  // If the constructor and destructor are not enough for setting up
  // and cleaning up each test, you can define the following methods:

  void SetUp() override {
     // Code here will be called immediately after the constructor (right
     // before each test).
  }

  void TearDown() override {
     // Code here will be called immediately after each test (right
     // before the destructor).
  }

  // Class members declared here can be used by all tests in the test suite
  // for Foo.
};

// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
  const std::string input_filepath = "this/package/testdata/myinputfile.dat";
  const std::string output_filepath = "this/package/testdata/myoutputfile.dat";
  Foo f;
  EXPECT_EQ(f.Bar(input_filepath, output_filepath), 0);
}

// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
  // Exercises the Xyz feature of Foo.
}

}  // namespace
}  // namespace project
}  // namespace my

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

:: testing :: InitGoogleTest() 함수는 googletest 플래그에 대한 명령 행을 구문 분석하고 인식 된 모든 플래그를 제거합니다. 이를 통해 사용자는 AdvancedGuide에서 다룰 다양한 플래그를 통해 테스트 프로그램의 동작을 제어 할 수 있습니다. RUN_ALL_TESTS()를 호출하기 전에 이 함수를 호출해야합니다. 그렇지 않으면 플래그가 제대로 초기화되지 않습니다.

Windows에서는 InitGoogleTest()도 넓은 문자열과 함께 작동하므로 UNICODE 모드로 컴파일 된 프로그램에서도 사용할 수 있습니다.

그러나 모든 주요 기능을 작성하는 것이 너무 많은 일이라고 생각하십니까? 우리는 전적으로 귀하에게 동의하며, 이것이 Google 테스트가 main()의 기본 구현을 제공하는 이유입니다. 요구 사항에 맞는 경우 테스트를 gtest_main 라이브러리와 연결하면 좋습니다.

참고 : ParseGUnitFlags ()는 InitGoogleTest()를 위해 더 이상 사용되지 않습니다.

알려진 제한

Google 테스트는 스레드 안전하도록 설계되었습니다. pthreads 라이브러리가 사용 가능한 시스템에서는 구현이 스레드로부터 안전합니다. 현재 다른 시스템 (예 : Windows)에서 두 스레드의 Google 테스트 어설 션을 동시에 사용하는 것은 안전하지 않습니다. 대부분의 테스트에서는 일반적으로 어설 션이 기본 스레드에서 수행되므로 문제가되지 않습니다. 도움이 필요한 경우 gtest-port.h에서 플랫폼에 필요한 동기화 프리미티브를 구현할 수 있습니다.







2020년 4월 7일 화요일

C모듈을 만들때 파일 규칙

C모듈을 만들 때 다음과 같은 파일 규칙을 사용한다.


헤더 파일  

          - 모듈의 인터페이스 정의
          - 단일 인스턴스 모듈의 헤더 파일은 함수 프로토타입만으로 구성
          - 추상 데이터 타입의 경우에는 함수 프로토타입 외에 전방 선언된 구조체의 포인터를 typedef               한 것도 추가된다.
          - 구조체 정의를 감추어서도 모듈의 상세 데이터를 감춘다.

소스 파일

          - 인터페이스 구현부 포함
          - 필요에 따라 비공개 도움 함수와 데이터도 포함
          - 모듈 구현부는 모듈 데이터의 무결성을 관리한다.
          - 추상 데이터타입의 경우에는 전방 선언한 구조체를 소스 파일에서 정의한다.

테스트 파일

          - 테스트 케이스를 포함한다.
          - 각 모듈에는 적어도 하나씩 테스트 파일이 포함된다.
          - 테스트 파일 하나에 테스트 그룹을 하나씩 포함시키는 것이 보통이지만 가끔은 여러개의 
            테스트 그룹을 포함시키기도 한다.
          -테스트 그룹은 그룹에 속하는 모든 테스트들에서 공통적으로 사용되는 데이터에 따라 나누어
           진다. 
          - 설정이 서로 많이 다른 테스트 케이스들은 별도의 테스트 그룹으로 나누고, 필요하다면 별도               의 테스트 파일로 떼어낸다.

모듈 초기화/정리 함수 

          - 숨겨진 데이터를 관리하는 모든 모듈에는 초기화 함수와 정리 함수가 있어야 한다.
          - 추상 데이터 타입이라면 그 내부가 완전히 감춰졌기 때문에 초기화 함수와 정리 함수가 반드시              필요하다.
      

2020년 2월 22일 토요일

googletest 설치

우분투 16.04 에서 googletest 설치 

1.  git clone https://github.com/google/googletest.git 에서 googletest를 다운로드한다.

2.  googletest폴더로 이동하면 아래와 같이 폴더 트리가 구성되어있다.
.
├── BUILD.bazel
├── CMakeLists.txt
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── WORKSPACE
├── appveyor.yml
├── ci
│   ├── build-linux-bazel.sh
│   ├── build-platformio.sh
│   ├── env-linux.sh
│   ├── env-osx.sh
│   ├── get-nprocessors.sh
│   ├── install-linux.sh
│   ├── install-osx.sh
│   ├── install-platformio.sh
│   ├── log-config.sh
│   └── travis.sh
├── googlemock
│   ├── CMakeLists.txt
│   ├── CONTRIBUTORS
│   ├── LICENSE
│   ├── README.md
│   ├── cmake
│   ├── docs
│   ├── include
│   ├── scripts
│   ├── src
│   └── test
├── googletest
│   ├── CMakeLists.txt
│   ├── CONTRIBUTORS
│   ├── LICENSE
│   ├── README.md
│   ├── cmake
│   ├── docs
│   ├── include
│   ├── samples
│   ├── scripts
│   ├── src
│   └── test
├── library.json
└── platformio.ini

3. googletest로 이동하여 CMakeLists.txt 파일에 아래를 추가해 준다.

add_definitions(-std=c++11)

4. googletest 폴더아래 libgtest.a 생성할 폴더(pcw1029)를 만들고 해당 폴더(pcw1029)에서 cmake ../googletest 명령을 실행하면 아래와 같이 몇가지 파일및 폴더가 생성된다.
.
├── BUILD.bazel
├── CMakeLists.txt
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── WORKSPACE
├── appveyor.yml
├── ci
│   ├── build-linux-bazel.sh
│   ├── build-platformio.sh
│   ├── env-linux.sh
│   ├── env-osx.sh
│   ├── get-nprocessors.sh
│   ├── install-linux.sh
│   ├── install-osx.sh
│   ├── install-platformio.sh
│   ├── log-config.sh
│   └── travis.sh
├── googlemock
│   ├── CMakeLists.txt
│   ├── CONTRIBUTORS
│   ├── LICENSE
│   ├── README.md
│   ├── cmake
│   ├── docs
│   ├── include
│   ├── scripts
│   ├── src
│   └── test
├── googletest
│   ├── CMakeLists.txt
│   ├── CONTRIBUTORS
│   ├── LICENSE
│   ├── README.md
│   ├── cmake
│   ├── docs
│   ├── include
│   ├── samples
│   ├── scripts
│   ├── src
│   └── test
├── library.json
├── pcw1029
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── Makefile
│   ├── bin
│   ├── cmake_install.cmake
│   └── lib
└── platformio.ini

5. pcw1029폴더에서 make하면 lib폴더에 라이브러가 생성된다.



2019년 8월 5일 월요일

3.2 C의 모듈화와 객체지향

3.2.1 C와 모듈화

고전적인 스택의 구현(git@github.com:pcw1029/modernC.git)
stack.h
#ifndef _STACK_H_
#define _STACK_H_

bool push(int val);
bool pop(int *pRet);

#endif

고전적인 스택의 구현
stack.c
#include<stdbool.h>
#include"stack.h"

int buf[16];
int top=0;

bool isStackFull(void){
    return top == sizeof(buf)/sizeof(int);
}

bool isStackEmpty(void){
    return top == 0;
}

bool push(Stack *p, int val){
    if(isStackFull(p)) return false;
    p->pBuf[p->top++] = val;
    return true;
}

bool pop(Stack *p, int *pRet){
    if(isStatckEmpty(p)) return false;
    *pRet = p->pBuf[--p->top];
    return true;
}

문제점 :
 변수와 함수의 스코프 : buf, top, isStackFull, isSteckEmpty가 전역 네임스페이스에 공개돼 있다. 만약 다른 소프코드에서 동일한 이름의 변수와 함수가 존재하면 충돌이 발생되어 링크에러를 발생한다. 이는 다른 프로그램에서 사용하기가 어려워진다.

해결책 :
 static 지시자를 사용한다.
static지시자를 붙인 함수나 변수의 이름은 해당 컴파일 단위 내에서만 유효하므로 충돌을 피할수 있다. 따라서 외부에 공개할 함수나 변수만 헤더에서 선언하고, 외부에 공개할 필요가 없는 변수나 함수는 static지시자를 붙이는 것이 C에서 흔히 볼수 있는 모듈화의 방법이다.

stack.c
#include<stdbool.h> 
#include "stack.h"

static int buf[16];
static int top=0;

static bool isStackFull(void){
    return top == sizeof(buf)/sizeof(int);
}

static bool isStatckEmpty(void){
    return top == 0;
}

bool push(int val){
    if(isStackFull()) return false;
    buf[top++] = val;
    return true;
}

bool pop(int *pRet){
    if(isStatckEmpty()) return false;
    *pRet = buf[--top];
    return true;
}


3.2.2 구조체를 이용한 자료 구조와 로직 분리
 앞에서 살펴본 예제는 아직도 문제 있습니다. 동일한 크기의 스택을 하나밖에 가질수 없는 문제입니다. 물론 함수나 변수의 이름에 숫자등을 붙여 비슷한 일을 하는 함수 또는 변수를 추가할수 있지만 그보다 구조체를 사용하여 스택을 구현하는데 필요한 데이터를 한데 모아서 그렇게 모은 데이터를 각 각 여러개 갖게 하는 방법입니다.

stack.h
#ifndef __STACK_H__ 
#define __STACK_H__

#include<stddef.h>

#ifdef __cplusplus
extern "C"{
#endif

typedef struct{
    int top;
    const size_t size;
    int *const pBuf;
}Stack;

bool push(Stack *p, int val);
bool pop(Stack *p, int *pRet);

#define newStack(buf){  \
    0, sizeof(buf)/sizeof(int), (buf) \
}

#ifdef __cplusplus
}
#endif

#endif

stack.c
#include<stdbool.h>
#include "stack.h"

static int buf[16];
static int top=0;

static bool isStackFull(const Stack *p){
    return p->top == p->size;
}

static bool isStatckEmpty(const Stack *p){
    return p->top == 0;
}

bool push(Stack *p, int val){
    if(isStackFull(p)) return false;
    p->pBuf[p->top++] = val;
    return true;
}

bool pop(Stack *p, int *pRet){
    if(isStatckEmpty(p)) return false;
    *pRet = p->pBuf[--p->top];
    return true;
}

stack.h파일에 정의된 newStack(buf) {0, sizeof(buf)/sizeof(int), (buf)} 는 아래와 같다.

int buf[16];
Stack stack = newStack(buf);

int buf[16];
Stack stack = {0, sizeof(buf)/sizeof(int), (buf)};
//top = 0, size = sizeof(buf)/sizeof(int), pBuf = buf

스택 데이터를 구조체로 분리해서 함수에 전달함으로서 간단하게 여러개의 스택을 만들수 있다.

int buf[16];
Stack stack = newStack(buf);

int buf2[18];
Stack stack2 = newStack(buf2);

3.2.3 C를 이용한 객체 지향
 스택에 저장할 수 있는 값의 범위를 제한하고 싶다고 가정해 보자. 예를 들어 0~9사이 값만 Push가 성공하고 그 외의 범위에 해당하는 숫자라면 여유공간이 존재해도 실패가 하도록 만들것이다.
쉽게 생각할수 있는것이 Push함수 전에 값을 확인하고 0~9사이에 값만 Push하도록 하면 된다.

bool pushWithRangeCheck(Stack*p, int val, int min, int max) {
    if(val<min || max<val) return false;
    return push(p, val);
}

위와 같은 방법은 인자의 개수가 많고, 이해하기 어렵고 push할때만다 인자값을 던지기 때문에 번거롭게 생각된다. 아래 코드는 좀 더 세련된 방법으로 스택을 생성하는 시점에 해당 범위를 전달하는 방법이 있다.

stack.h
typedef struct{
    int top;
    const size_t size;
    int *const pBuf;
    
    const bool needRangeCheck;
    const int min;
    const int max;
}Stack;
...
#define newStackWithRangeCheck(buf, min, max) { \ 
    0, sizeof(buf)/sizeof(int), (buf), \ 
    true, min, max
}

stack.c
                                                                                                          
static bool isRangeOk(const Stack *p, int val){                                                           
    return ! p->needRangeCheck || (p->min <= val && val <= p->max)                                        
}   

bool push(Stack *p, int val){                                                                             
    if(! isRangeOk(p,val) || isStackFull(p)) return false;                                                
    p->pBuf[p->top++] = val;
    return true;                                                                                          
}

범위 검사가 필요한지 여부를 나타내는 변수 needRangeCheck 그리고 값의 유효 범위를 나타내는 변수 min, max를 구조체에 포함시키고, 범위 검사 기능을 가진 스택을 생성하기 위한 매크로를 준비했다.

int buf[16];
Stack stack = newStackWithRangeCheck(buf, 0, 9);

이 예제에서는 0에서 9까지의 범위 검사 기능을 가진 스택을 생성한다.

이 코드에는 아래와 같은 문제점을 가지고 있습니다.
1. 범위 검사 기능이 없는 스택을 생성한 경우에도 needRnageCheck, min, max같은 불필요한 맴버를 스택에 보유해야 한다.
2. 스택에 또다른 검사 기능을 추가하고자 한다면 구조체에 멤버를 추가해야 한다. 구조체 내부에 제공하려는 기능에 필요한 모든 멤버를 가져야 하므로 push함수도 그 기능때문에 크기가 커진다. 기능의 수가 많아지면 곧장 걷잡을 수 없을 만큼 복잡해진다.

*생각하기
1. 이번에 추가된 needRangeCheck, min, max 맴버들은 스택의 다른 맴버와 같은 곳에 둘 필요가 있는가?
2. 이들 맴버들은 isRangeOk에서만 사용되는 것들이며,  스택을 구성하는 모든 함수가 접근할수 있는 곳에 두는것이  적절한가?
이 위치면 스코프가 너무 넓다. 우선 이부분을 분리해보겠다.

stack.h

#include<stdbool.h>
#include<stddef.h>

#ifdef __cplusplus
extern "C"{
#endif

typedef struct{
    const int min;
    const int max;
}Range;

typedef struct{
    int top;
    const size_t size;
    int *const pBuf;
    const Range* const pRange;
}Stack;

bool push(Stack *p, int val);
bool pop(Stack *p,int *pRet);

#define newStack(buf){ \
    0, sizeof(buf)/sizeof(int), (buf), \
    NULL \
}

#define newStackWithRangeCheck(buf, pRange) { \
    0, sizeof(buf)/sizeof(int), (buf), \
    pRange \
}


#ifdef __cplusplus
}

stack.c

#include<stdio.h>                                                                                     
#include "stack.h"                                                                                    
static bool isRangeOk(const Range* p, int val){                                                       
    return p == NULL || (p->min <= val && val <= p->max);                                             
}                                                                                                     
                                                                                                      
static bool isStackFull(Stack *p) {                                                                   
    return p->top == p->size;                                                                         
}                                                                                                     
                                                                                                      
static bool isStackEmpty(Stack *p) {                                                                  
    return p->top == 0;                                                                               
}                                                                                                     
                                                                                                      
bool push(Stack *p, int val) {                                                                        
    if(! isRangeOk(p->pRange, val) || isStackFull(p)) return false;                                   
    p->pBuf[p->top++] = val;                                                                          
    return true;                                                                                      
}                                                                                                     
                                                                                                      
bool pop(Stack *p, int *pRet) {                                                                       
    if(isStackEmpty(p)) return false;                                                                 
    *pRet = p->pBuf[--p->top];                                                                        
    return true;                                                                                      
} 

체크기능을 범용화 한다
지금까지는 상하 한계 검사를 수행하는 구조로 만들었지만 값 검사의 대상은 한계말고도 많습니다.
예를 들어 직전에 Push한 값 이상의 값을 받아들이는 조건이 들어있는 스택을 만들려고 할때 현재 구조는 구현 할수 없지만 입력값 검사를 번용적으로 바꾸면 가능해 집니다.

먼저, Validator라는 구조체에 입력값을 검사하는 범용적인 역할을 구현하겠습니다.







2019년 6월 13일 목요일

CPPUTEST 우분투16.04 설치


  1.  CPPUTEST 다운로드 
    1. 다운로드 주소 ( https://github.com/cpputest/cpputest )
    2. V3.7.2 다운로드
    3. cpputest site ( https://cpputest.github.io/ )
  2. 설치
    1. GitHub에서 다운로드 후 압축을 풀어준다.
      1. $ tar xfz cpputest-3.7.2.tar.gz
      2. $ cd cpputest-3.7.2
    2. cpputest_build로 이동 후 설치진행한다.
      1.  $ autoreconf .. -i
      2. $ ../configure
      3. $ make
      4. $ make install 
    3. lib 폴더 링크 걸기
      1. ln -s cpputest_build/lib ./lib

ZCU102 CDMA with BRAM




  1. H/W 디자인 
    1. ZCU102 Re-customize IP 설정
      1. PS-PL Configuration 
        1. PS-PL Interface 
          1. Master Interface 
            1. AXI HPM0 FPD : Checked  
              1. AXI HPM0 FPD Data Width : 32
            2. AXI HPM1 FPD : Checked 
              1. AXI HPM0 FPD Data Width : 128 
            3. AXI HPM0 LPD : Checked
              1. AXI HPM0 FPD Data Width : 32 
          2. Slave Interface
            1. AXI HP
              1. AXI HPC0 FPD : Checked
                1. AXI HPC0 FPD Data Width : 128
    2. CDMA IP 코어 추가 
      1. Write/Read Data Width : 128
      2. Write/Read Burst Size : 4
      3. Address Width : 32
      4. 연결
        1. S_AXI_LITE ----> Zynq AXI HPM0 LPD
        2. M_AXI ----> Zynq AXI HPC0 FPD
    3. AXI BRAM Controller IP 코어 추가 
      1. AXI Protocol : AXI4
      2. Data Width : 128
      3. Number of BRAM interface : 1
      4. Enable ECC : No
    4. Block Memory Genterator IP 코더 추가
      1. Basic
        1. Mode : BRAM Controller
        2. Memory Type : True Dual Port RAM
      2. Other Options
        1. Enable Safety Circuit : UnChecked
    5. ㅇㅇ

VITIS Git + Doxygen Config

 Doxygen Configure 1. Vitis 메뉴의 Window->Preference의 C/C++ -> Editor의 Documentation tool comments 기본 설정값을 Doxygen으로 변경 설정 후 함수 바로 위에서 /...