'Study/Programming'에 해당되는 글 7건

  1. 2010년 01월 25일 Visual Studio .Net 프로젝트의 파일 확장자 - 소류
  2. 2009년 09월 02일 [Debug] MS C++ 디버깅 매직넘버 - 소류
  3. 2009년 02월 02일 Casting in C++: Bringing Safety and Smartness to Your Programs - 소류
  4. 2009년 01월 28일 Visual Studio 6.0에서 Doxygen 사용하기 - 소류
  5. 2007년 04월 10일 STL : 실시간에 정렬 기준 정의하기<string, string> (2) - 소류
  6. 2007년 04월 04일 String Conversions - 소류
  7. 2007년 04월 02일 Const - 소류

Visual C++ 프로젝트를 만들 때 새 솔루션을 만들거나 솔루션에 프로젝트를 추가할 수 있습니다. 하나의 솔루션에 포함된 여러 프로젝트를 사용하여 중요한 응용 프로그램을 개발하는 경우가 많습니다.

프로젝트는 보통 EXE 또는 DLL 중 하나를 생성합니다. 프로젝트는 서로 종속성을 가질 수 있습니다. Visual C++ 환경에서는 프로젝트 내부의 종속성 및 프로젝트 간의 종속성을 모두 확인합니다. 각 프로젝트에는 핵심 소스 코드가 있으며 프로젝트 종류에 따라 프로젝트의 여러 측면을 포함하는 여러 종류의 파일이 있습니다. 어떤 내용이 포함된 파일인지는 파일의 확장명을 통해 식별할 수 있습니다. Visual Studio 개발 환경에서는 파일 확장명을 기반으로, 빌드하는 동안 해당 파일 내용을 어떻게 처리할 것인지를 결정합니다.

다음 표는 Visual C++ 프로젝트에서 일반적으로 사용되는 파일 형식과 파일 확장명입니다. Projname은 프로젝트 이름을 나타냅니다.



파일 확장명형식내용
.asmx소스배포 파일
.asp소스Active Server Page 파일
.atp프로젝트응용 프로그램 템플릿 프로젝트 파일
.bmp, .dib, .gif, .jpg, .jpe, .png리소스일반 이미지 파일
.bsc컴파일브라우저 코드 파일
.cpp; .c소스응용 프로그램의 주 소스 코드 파일
.cur리소스커서 비트맵 그래픽 파일
*.dbp프로젝트데이터베이스 프로젝트 파일
.disco소스동적 검색 문서 파일. XML Web services 검색을 처리합니다.
.exe, .dll프로젝트실행 파일 또는 동적 연결 라이브러리 파일
.h소스헤더 또는 포함 파일
.htm, .html, .xsp, .asp, .htc, .hta, .xml리소스일반 웹 파일
.HxC프로젝트도움말 프로젝트 파일
.ico리소스아이콘 비트맵 그래픽 파일
.idb컴파일클래스 정의와 소스 파일 간의 종속성 정보가 들어 있는 상태 파일. 최소 다시 빌드 및 증분 컴파일을 하는 동안 컴파일러에서 사용할 수 있습니다. /Fd 컴파일러 옵션을 사용하여 .idb 파일 이름을 지정합니다. 자세한 내용은 /Gm(최소 다시 빌드 사용)을 참조하십시오.
.idl컴파일인터페이스 정의 언어 파일. 자세한 내용은 Platform SDKInterface Definition (IDL) File을 참조하십시오.
.ilk링크증분 링크 파일. 자세한 내용은 /INCREMENTAL을 참조하십시오.
.map링크링커 정보를 포함하는 텍스트 파일. /Fm 컴파일러 옵션을 사용하여 맵 파일 이름을 지정합니다. 자세한 내용은 /MAP를 참조하십시오.
.ncb해결 방법컴파일하지 않는 브라우저 파일.
.obj, .o 컴파일되었지만 링크되지 않은 개체 파일
.pch디버그미리 컴파일된 헤더 파일
.pdb디버그프로그램 디버그 데이터베이스 파일. 자세한 내용은 PDB 파일을 참조하십시오.
.rc, .rc2리소스리소스를 생성하는 리소스 스크립트 파일
.sbr컴파일소스 브라우저 중간 파일. BSCMAKE를 위한 입력 파일
.sln해결 방법솔루션 파일
.suo해결 방법솔루션 옵션 파일
.srf프로젝트서버 지시 파일. 이 파일에는 ATL 서버 응용 프로그램을 위한 HTML 코드가 들어 있습니다.
.txt리소스텍스트 파일. 보통 "추가 정보" 파일
.vap프로젝트Visual Studio Analyzer 프로젝트 파일
.vbg해결 방법호환 가능한 프로젝트 그룹 파일
.vbp, .vip, .vbproj프로젝트Visual Basic 프로젝트 파일
*.vcproj프로젝트Visual C++ 프로젝트 파일. 자세한 내용은 프로젝트 파일 및 메이크파일을 참조하십시오.
.vdproj프로젝트Visual Studio deployment 프로젝트 파일
.vmx프로젝트매크로 프로젝트 파일
.vup프로젝트유틸리티 프로젝트 파일
크리에이티브 커먼즈 라이센스
Creative Commons License
2010년 01월 25일 16시 57분 2010년 01월 25일 16시 57분
TAG

[Debug] MS C++ 디버깅 매직넘버

MS C++ 디버깅시 자주 등장하는 매직넘버들~

0xabababab HeapAlloc으로 메모리 할당 후 가드 바이트에 채워진 값
0xbaadf00d LocalAlloc(LMEM_FIXED)으로 메모리 할당된 후 초기화 되지 않은 값
0xcccccccc 초기화 되지 않은 스택 메모리
0xcdcdcdcd 메모리 할당 후 초기화 되지 않은 힙 메모리
0xdddddddd 해제된 힙 메모리
0xfdfdfdfd 할당된 메모리의 전후 가드용 바이트에 채워지는 값
0xfeeefeee 힙 메모리를 해제한 후 채워지는 값 [HeapFree()]


크리에이티브 커먼즈 라이센스
Creative Commons License
2009년 09월 02일 13시 54분 2009년 09월 02일 13시 54분
TAG ,

Casting in C++: Bringing Safety and Smartness to Your Programs

By G. Bowden Wise

The new C++ standard is full of powerful additions to the language: templates, run-time type identification (RTTI), namespaces, and exceptions to name a few. Rather than talk about one of these ``major'' extensions, I will discuss one of the minor extensions: the new C++ casting operators.

The C++ draft standard includes the following four casting operators:

  • static_cast
  • const_cast
  • dynamic_cast, and
  • reinterpret_cast.

These new operators are intended to remove some of the holes in the C type system introduced by the old C-style casts.

In this article we will learn about casting in general, discuss the problems with the old C-style cast, and take a look at the new C++ casting operators in detail.

Why Cast?

Casts are used to convert the type of an object, expression, function argument, or return value to that of another type. Some conversions are performed automatically by the compiler without intervention by the programmer. These conversions are called implicit conversions. The standard C++ conversions and user-defined conversions are performed implicitly by the compiler where needed. Other conversions must be explicitly specified by the programmer and are appropriately called explicit conversions.

Standard conversions are used for integral promotions (e.g., enum to int), integral conversions (e.g., int to unsigned int), floating point conversions (e.g., float to double), floating-integral conversions (e.g., int to float), arithmetic conversions (e.g., converting operands to the type of the widest operand before evaluation), pointer conversions (e.g., derived class pointer to base class pointer), reference conversions (e.g., derived class reference to base class reference), and pointer-to-member conversions.

You can provide a user-defined conversion from a class X to a class Y by providing a constructor for Y that takes an X as an argument:

   Y(const X& x)

or by providing a class Y with a conversion operator:

    operator X()

When a type is needed for an expression that cannot be obtained through an implicit conversion or when more than one standard conversion creates an ambiguous situation, the programmer must explicitly specify the target type of the conversion.

In C, an expression, expr, of type S can be cast to another type T in one of the following ways. By using an explicit cast:

   (T) expr

or by using a functional form:

   T(expr)

We will refer to either of these constructs as the old C-style casts.

The old C-style casts have several shortcomings. First, the syntax is the same for every casting operation. This means it is impossible for the compiler (or users) to tell the intended purpose of the cast. Is it a cast from a base class pointer to a derived class pointer? Does the cast remove the ``const-ness'' of the object? Or, is it a conversion of one type to a completely unrelated type? The truth is, it is impossible to tell from the syntax. As a result, this makes the cast harder to comprehend, not only by humans, but also by compilers which are unable to detect improper casts.

Another problem is that the C-style casts are hard to find. Parentheses with an identifier between them are used all over C++ programs. There is no easy way to ``grep'' a source file and get a list of all the casts being performed.

Perhaps the most serious problem with the old C-style cast is that it allows you to cast practically any type to any other type. Improper use of casts can lead to disastrous results. The old C-style casts have created a few holes in the C type system and have also been a souce of confusion for both programmers and compilers. Even in C++, the old C-style casts are retained for backwards compatibility. However, using the new C++ style casting operators will make your programs more readable, type-safe, less error-prone, and easier to maintain.

The New C++ Casting Operators

The new C++ casting operators are intended to provide a solution to the shortcomings of the old C-style casts by providing:

  • Improved syntax. Casts have a clear, concise, although somewhat cumbersome syntax. This makes casts easier to understand, find, and maintain.
  • Improved semantics. The intended meaning of a cast is no longer ambiguous. Knowing what the programmer intended the cast to do makes it possible for compilers to detect improper casting operations.
  • Type-safe conversions. Allow some casts to be performed safely at run-time. This will enable programmers to check whether a particular cast is successful or not.

C++ introduces four new casting operators:

  • static_cast, to convert one type to another type;
  • const_cast, to cast away the ``const-ness'' or ``volatile-ness'' of a type;
  • dynamic_cast, for safe navigation of an inheritance hierarchy; and
  • reinterpret_cast, to perform type conversions on un-related types.

All of the casting operators have the same syntax and are used in a manner similar to templates. For example, to perform a static_cast of ptr to a type T we write:

   T* t = static_cast<T> (ptr);

As we will soon see, static_cast is the most general and is intended as a replacement for most C-style casts. The other three forms are for specific circumstances to be discussed below.

The static_cast Operator

The static_cast operator takes the form

    static_cast<T> (expr)

to convert the expression expr to type T. Such conversions rely on static (compile-time) type information.

Subject to certain restrictions, you may use static_cast to convert a base class pointer to a derived class pointer, perform arithmetic conversions, convert an int to anenum, convert a reference of type X& to another reference of type Y&, convert an object of type X to an object of type Y, and convert a pointer-to-member to another pointer-to-member within the same class hierarchy.

Internally, static_casts are used by the compiler to perform implicit type conversions such as the standard conversions and user-defined conversions. In general, a complete type can be converted to another type so long as some conversion sequence is provided by the language.

The downcast of a base class pointer X* to a derived class pointer Y* can be done statically only if the conversion is unambiguous and X is not a virtual base class. Consider this class hierarchy:

   class BankAcct
         { /* ... */ }
   class SavingsAcct : public BankAcct
         { /* ... */ }

Given a base class pointer, we can cast it to a derived class pointer:

   void f (BankAcct* acct)
   {
      SavingsAcct* d1 =
        static_cast<SavingsAcct*>(acct);
   }

This is called a downcast. The static_cast operator allows you to perform safe downcasts for non-polymorphic classes.

Note that static_cast relies on static (compile-time) type information and does not perform any run-time type checking. This means that if acct does, in fact, not refer to an actual SavingsAcct the result of the cast is undefined. Borland C++ 4.5, seemingly incorrectly, still performs the conversion, however. Your compiler mileage may vary. If you want to use run-time type information during conversion of polymorphic class types, use dynamic_cast. It is not possible to perform a downcast from a virtual base class using a static_cast; you must use a dynamic_cast.

More generally, a static_cast may be used to perform the explicit inverse of the implicit standard conversions. A conversion from type S to T can only be done if the conversion from type T to S is an implicit conversion. Also, the ``const-ness'' of the original type, S, must be preserved. You cannot use static_cast to change ``const-ness''; use const_cast instead.

One of the more common uses of static_cast is to perform arithmetic conversions, such as from int to double. For example, to avoid the truncation in the following computation:

   int   total = 500;
   int   days  = 9;
   double rate = total/days;

We can write:

   double rate =
          static_cast<double>(total)/days;

static_cast may also be used to convert an integral type to an enumeration. Consider:

   enum fruit {apple=0,orange,banana};
   int i  1 = 2;
   fruit f1 = static_cast<fruit> (i1);

The conversion results in an enumeration with the same value as the integral type provided the integral value is within the range of the enumeration. The conversion of an integral value that is not within the range of the enumeration is undefined.

You may also use static_cast to convert any expression to a void, in which case the value of the expression is discarded.

One interesting side effect of the old C-style casts, was to gain access to a private base class of a derived class. Consider this hierarchy:

   class Base
   {
   public:
      Base() : _data(999) {}
      int  Data() const {return _data;}
   private:
      int _data;
   };

   class Derived : private Base
   {
   public:
      Derived () : Base() {}
   };

   Derived* d1 = new Derived;

Normally, you should not be able to access Data() through the pointer d1. However, using an old C-style cast, we can:

   Base* b1 = (Base*) d1;
   int i = b1->Data(); // works!

The good news is that if you attempt to use static_cast:

   Base* b1 = static_cast<Base*>(d1);

the compiler will correctly report that Base is inaccessible because it is a private base class.

Another unfortunate hole created in the type system by the old C-style casts results with incomplete types. Consider:

   class X; // incomplete
   class Y; // incomplete

The old C-style casts, let us cast from one incomplete type to another! Here is an example:

   void f(X* x)
   {
      Y* y = (Y*) x;  // works!
   }

Thankfully, this hole has also been plugged by static_cast:

   void f(X* x)
   {
      Y* y = static_cast<Y*> x;  // fails
   }

The const_cast Operator

The const_cast operator takes the form

    const_cast<T> (expr)

and is used to add or remove the ``const-ness'' or ``volatile-ness'' from a type.

Consider a function, f, which takes a non-const argument:

   double f(double& d);

However, we wish to call f from another function g:

   void g (const double& d)
   {
     val = f(d);
   }

Since d is const and should not be modified, the compiler will complain because f may potentially modify its value. To get around this dilemma, we can use a const_cast:

   void g (const double& d)
   {
      val = f(const_cast<double&>(d));
   }

which strips away the ``const-ness'' of d before passing it to f.

Another scenario where const_cast is useful is inside const functions. Remember that when you make a member function const, you are telling your users (and the compiler) that calling this function will not change the value of the object. However, in some cases, we find that it is sometimes still necessary to change the value of some internal data members inside a function that is const. For example, consider class B:

   class B
   {
   public:
      B()  {}
      ~B() {}
      void f() const;
   private:
      int  _count;
   };

Suppose that, f(), which is declared to be const, must modify _count whenever it is called:

   void B::f() const
   {
      _count += 1;
   }

The compiler will not allow _count to be changed because the function is const. Just how does the compiler perform this magic? It turns out that the type of the internal thispointer helps the compiler perform this check.

Every non-static member function of a class C has a this pointer. For non-const member functions of class Cthis has type

   C * const

This means that this is a constant pointer. In other words, you cannot change what the pointer this points to, after all, that would be disastrous, wouldn't it? However, you can still change what ever this points to (i.e., you can change data members of class C).

For const member functions of class Cthis has a type of

  const C * const

Not only is this a constant pointer but also what is pointed to is constant. So the data members of C may not be changed through the this pointer. This is how the compiler ensures that you do not modify data members inside const functions.

Examining the member function B::f again, the statement _count is actually interpreted as this->_count. But since this has type const B * const, it cannot be used to change the value of _count so the compiler reports an error.

We can, however, use const_cast to cast away the ``const-ness'' of this:

   void B::f() const
   {
      B* const localThis =
               const_cast<B* const>(this);
      localThis->_count += 1;
   }

Actually, you should not be casting away the ``const-ness'' of this using const_cast. C++ now has the keyword mutable for those data members whose value may be changed by const functions. By declaring _count as:

   mutable int _count;

We can use the original implementation of B::f without casting away the ``const-ness'' of this.

const_cast can also be used to strip away the ``volatile-ness'' of an object in a similar manner. You cannot use const_cast for any other types of casts, such as casting a base class pointer to a derived class pointer. If you do so, the compiler will report an error.

The dynamic_cast Operator

The dynamic_cast operator takes the form

   dynamic_cast<T> (expr)

and can be used only for pointer or reference types to navigate a class hierarchy. The dynamic_cast operator can be used to cast from a derived class pointer to a base class pointer, cast a derived class pointer to another derived (sibling) class pointer, or cast a base class pointer to a derived class pointer. Each of these conversions may also be applied to references. In addition, any pointer may also be cast to a void*.

The dynamic_cast operator is actually part of C++'s run-time type information, or RTTI, sub-system. As such, it has been provided for use with polymorphic classes -- those classes which have at least one virtual function. Use static_cast to perform conversions between non-polymorphic classes.

All of the derived-to-base conversions are performed using the static (compile-time) type information. These conversions may, therefore, be performed on both non-polymorphic and polymorphic types. These conversions will produce the same result if they are converted using a static_cast. These conversions are fairly straightforward so we won't discuss them further.

Conversions down the hierarchy from base to derived, or across a class hierarchy, rely on run-time type information and can only be performed on polymorphic types. Such conversions can now be performed safely since dynamic_cast will indicate whether the conversion is successful. When performing a dynamic_cast on a pointer, a null pointer is returned when the cast is unsuccessful. When a reference is being cast, a Bad_cast exception is thrown.

Let's look at the power of run-time type conversions by revisiting the bank account hierarchy introduced above with static_cast. Recall that when acct does not actually point to a SavingsAcct object, the result of the static_cast is undefined. Since BankAcct has at least one virtual function, it is a polymorphic class. We can use a dynamic_castinstead to check that the cast was successful:

   void f (BankAcct* acct)
   {
      SavingsAcct* d1 =
         dynamic_cast<SavingsAcct*>(acct);
      if (d1)
      {
         // d1 is a savings account
      }
   }

Let's expand our bank account hierarchy to include a few more types of accounts, such as a checking account and a money market account. Let's suppose we also want to extend the functionality so that we can credit the interest for all savings and money market accounts in our database. Suppose further that BankAcct is part of a vendor library; we are not able to add any new members functions to BankAcct since we do not have the source code.

Clearly, the best way to incorporate the needed functionality would be to add a virtual function, creditInterest() to the base class, BankAcct. But since we are not able to modify BankAcct, we are unable to do this. Instead, we can employ a dynamic_cast to help us.

We add the method creditInterest() to both SavingsAcct and MMAcct classes. The resulting class hierarchy looks like:

   class BankAcct    { /* ... */ }
   class SavingsAcct : public BankAcct
   {
   public:
     // ...
     void computeInterest();
   }
   class MMAcct : public BankAcct
   {
   public:
     // ...
     void computeInterest();
   }

We can now compute interest for an array of BankAcct*s:

   void DoInterest (BankAcct* a[],
                    int num_accts)
   {
     for (int i = 0; i < num_accts; i++)
     {
       // Check for savings
       SavingsAcct* sa =
       dynamic_cast<SavingsAcct*>(accts[i]);
       if (sa)
       {
          sa->creditInterest();
       }

       MMAcct* mm =
       dynamic_cast<MMAcct*>(accts[i]);
       if (mm)
       {
          mm->creditInterest();
       }
     }
   }

dynamic_cast will return a null pointer if the cast is not successful. So only if the pointer is of type SavingsAcct* or MMAcct* is interest credited. dynamic_cast allows you to perform safe type conversions and lets your programs take appropriate actions when such casts fail.

When a pointer is converted to a void*, the resulting object points to the most derived object in the class hierarchy. This enables the object to be seen as raw memory. Meyers [3] demonstrates how a cast to void* can be used to determine if a particular object is on the heap.

The reinterpret_cast Operator

The reinterpret_cast operator takes the form

   reinterpret_cast<T> (expr)

and is used to perform conversions between two unrelated types. The result of the conversion is usually implementation dependent and, therefore, not likely to be portable. You should use this type of cast only when absolutely necessary.

reinterpret_cast can also be used to convert a pointer to an integral type. If the integral type is then converted back to the same pointer type, the result will be the same value as the original pointer.

Meyers [3] shows how reinterpret_casts can be used to cast between function pointer types.

Summary

The new C++ cast operators enable you to develop programs which are easier to maintain and understand, and perform some conversions safely. Casts should not be taken lightly. As you convert your old C-style casts to use the new C++ casting operators, ask yourself if a cast is really needed there. It may be that you are using a class hierarchy in a way not originally intended or that you may be able to do the same thing with virtual functions.

References

1
Ellis, M. A., and Stroustrup, B. The Annotated C++ Reference Manual. Addison-Wesley, Reading, Mass., 1990.
2
Meyers, S. Effective C++: 50 Specific Ways to Improve Your Programs and Designs. Addison-Wesley, Reading, Mass., 1992.
3
Meyers, S. More Effective C++: 35 New Ways to Improve Your Programs and Designs. Addison-Wesley, Reading, Mass., 1996.
4
Stroustrup, B. The Design and Evolution of C++. Addison-Wesley, New York, 1994.
크리에이티브 커먼즈 라이센스
Creative Commons License
2009년 02월 02일 10시 19분 2009년 02월 02일 10시 19분
TAG ,

Visual Studio 6.0에서 Doxygen 사용하기


4. html help compiler (version 1.3) : 다운로드(htmlhelp.exe)

1. doxygen 설치하기
* 다운로드받은 doxygen-1.3.5-setup.exe 파일은 윈도우용 설치 프로그램 파일이다. 실행시킨 뒤 원하는 폴더에 설치한다.(디폴트값 : C:\Program Files\doxygen)

* doxygen이 설치된 경로 아래의 bin 디렉토리에서 다음과 같은 도스 명령을 실행시킨다.

doxygen -g [템플릿파일명]

위 도스 명령에서 템플릿파일명을 지정하지 않으면 Doxyfile이라는 이름의 파일이 생성된다.

* 생성된 템플릿 파일을 편집한다. 편집하기를 추천하는 부분은 다음과 같다.

OUTPUT_LANGUAGE = Korean

OUTPUT_LANGUAGE의 디폴트값은 English로 되어 있는데 Korean으로 변경하면 한글화된 문서를 얻을 수 있다.

EXTRACT_ALL = YES

생성 후 비어있는 문서항목들도 모두 표시한다.

EXTRACT_PRIVATE = YES

private 멤버들을 문서화할 것인지 여부.

EXTRACT_STATIC = YES

static 멤버들을 문서화할 것인지 여부

SOURCE_BROWSER = YES

소스에 대한 직접적인 정보링크를 만들것인지 여부

HAVE_DOT = YES

다음에 설명하게 될 클래스관계 그림 생성 여부(by graphviz)

2. graphviz 설치하기
이 프로그램은 클래스간의 관계를 알아보기 쉽게 그림으로 만들어내는 기능을 수행한다.

위에서 다운로드 받은 파일(graphviz-1.10.exe)은 윈도우용 설치 프로그램 파일이다. 그대로 실행시키면 디폴트값으로 "C:\Program Files\ATT\Graphviz" 경로에 설치가 된다.

3. Doxbar 설치하기
이 프로그램은 Visual Studio 6.0에서 Doxygen을 사용하기 쉽게 해주는 애드인 프로그램이다.

다운로드받은 파일(doxbar-0.35-bin.zip)의 압축을 풀면 다음과 같은 두 개의 파일을 볼 수 있다.

doxbar.chm, doxbar.dll

위 두 개의 파일을 적당한 디렉토리에 복사한다. 예를 들어 C:\Program Files\doxygen\Doxbar 디렉토리를 새로 만들어서 그 안에 집어넣는다.

4. Doxbar 설정하기
지금까지 doxygen, graphviz, doxbar를 모두 설치 완료하였다. 이제부터는 doxygen을 사용하여 프로젝트를 문서화하기 위한 설정 방법을 알아보도록 하겠다.

* Visual Studio 6.0을 실행시키고 Tools - Customize... 메뉴를 선택한다. 그리고 Add-ins and Macro Files 탭을 선택한 뒤 Browse 버튼을 눌러서 Doxbar.dll을 선택해주도록 한다.

그림 1.
사용자 삽입 이미지

Doxbar.dll을 등록시키면 위 그림에서와 같이 Doxbar.DSAddIn.1이 추가된다. 이 항목을 선택하고 Close 버튼을 누르면 다음과 같은 툴바가 Visual Studio에 추가된다.

그림 2.
사용자 삽입 이미지

* 다시 Visual Studio의 Tools - Customize 메뉴를 선택하고 Tools 탭을 선택한다.

그림 3.
사용자 삽입 이미지


위 그림에 나와있는 것과 같이 Doxygen이라는 항목을 추가하고 Command 항목값으로 C:\Temp\rundoxy.bat 을 등록한다.

여기에서 등록한 rundoxy.bat 파일을 실제로 존재하지 않는 입력값이다. 따라서 Close 버튼을 누르면 실제로 존재하지 않으므로 수정하겠느냐라는 메시지박스가 나타나는데 아니오로 선택하고 종료하면 된다.
* 그림 2.에서 보이는 Doxbar 툴바 버튼들 중에서 왼쪽에서 두 번째 위치한 버튼이 Doxygen에 대한 환경설정 기능을 수행한다.

환경설정을 수행하기에 앞서 Visual Studio의 Tools 메뉴를 선택하여 방금 전 추가한 Doxygen 툴의 번호가 몇인지를 확인하도록 한다.

그림 4.
사용자 삽입 이미지


위 그림에서는 10으로 표시되고 있다.

* Doxbar 툴바의 두 번째 버튼을 선택하면 다음과 같은 환경설정 대화상자가 나타난다.

그림 5.
사용자 삽입 이미지

앞에서 추가한 Doxygen 툴 메뉴의 번호대로 UserTool<번호>를 입력한다.

그림 6.
사용자 삽입 이미지


위 그림에서는 Doxygen이 실행될 때 실시간으로 만들어지는 배치파일의 경로, doxygen.exe의 경로, 디폴트 템플릿 파일의 경로, 도움말 컴파일러의 경로 등을 설정하고 있는 모습을 보여주고 있다.

그림 7.
사용자 삽입 이미지

위 그림에서 보이고 있는 값들은 디폴트값이다. 그대로 사용하면 된다.

5. Doxygen 실행하기

이제 마지막으로 doxygen을 실행시켜서 프로젝트 문서화를 해볼 차례이다. Doxbar의 맨 왼쪽 버튼을 누르면 Output 윈도우에 주르륵 표시되면서 문서화가 이루어진다.
크리에이티브 커먼즈 라이센스
Creative Commons License
2009년 01월 28일 11시 35분 2009년 01월 28일 11시 35분
TAG ,

class RuntimeStringCmp {
public:
 // 비교 기준을 위한 상수
 enum cmp_mode {normal, nocase};
 
private:
 // 실제 비교 모드
 const cmp_mode mode;
 
 // 대/소문자를 구별하지 않고 비교하기 위한 보조 함수
 static bool nocase_compare(char c1, char c2)
 {
  return toupper((c1) < toupper(c2));
 }

public:
 // 생성자: 비교 기준으로 초기화된다.
 RuntimeStringCmp(cmp_mode m=normal) : mode(m) {
 }

 // 비교
 bool operator() (const std::string& s1, const std::string& s2) const {
  if(mode == normal) {
   return s1<s2;
  }
  else {
   return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), nocase_compare);
  }
 }
};

크리에이티브 커먼즈 라이센스
Creative Commons License
2007년 04월 10일 15시 57분 2007년 04월 10일 15시 57분

String Conversions

String to Hex

sscanf(string, %04X, &your_word16); // where string = your string and
                                                     // 04 = length of your string and X = hex

Hex to CString

CString Str; unsigned char Write_Buff[1]; Write_Buff[0] = 0x01; Str.Format("0x0%x",Write_Buff[0]);

COleVariant to CString

CString strTemp; COleVariant Var; Var = "FirstName"; strTemp = Var.bstrVal; AfxMessageBox(strTemp);

CString to char pointer

CString MyString = "ABCDEF"; char * szMyString = (char *) (LPCTSTR) MyString;
char *pBuffer = new char[1024]; CString strBuf = "Test"; pBuffer = strBuf.GetBuffer(sizeof(pBuffer));

char pointer to CString

char * mystring = "12345"; CString string = mystring;

Double to CString including the fractional part

CString strValue,strInt, strDecimal; int decimal,sign; double dValue = 4.125; strValue = _fcvt(dValue,6,&decimal,&sign); // Now decimal contains 1 because there is  // only one digit before the . strInt = strValue.Left(decimal); // strInt contains 4 strDecimal = strValue.Mid(decimal); // strDecimal contains 125 CString strFinalVal; strFinalVal.Format("%s.%s",strInt,strDecimal); // strFinalVal contains 4.125

Double To CString

CString strValue; int decimal,sign; double dValue = 123456789101112; strValue = _ecvt(dValue,15,&decimal,&sign);

CString To Double

strValue = "121110987654321"; dValue = atof(strValue);

CString to LPCSTR

CString str1 = _T("My String"); int nLen = str1.GetLength(); LPCSTR lpszBuf = str1.GetBuffer(nLen); // here do something with lpszBuf........... str1.ReleaseBuffer();

CString to LPSTR

CString str = _T("My String"); int nLen = str.GetLength(); LPTSTR lpszBuf = str.GetBuffer(nLen); // here do something with lpszBuf........... str.ReleaseBuffer();

CString to WCHAR*

CString str = "A string here" ; LPWSTR lpszW = new WCHAR[255]; LPTSTR lpStr = str.GetBuffer( str.GetLength() ); int nLen = MultiByteToWideChar(CP_ACP, 0,lpStr, -1, NULL, NULL); MultiByteToWideChar(CP_ACP, 0, lpStr, -1, lpszW, nLen); AFunctionUsesWCHAR( lpszW ); delete[] lpszW;

LPTSTR to LPWSTR

int nLen = MultiByteToWideChar(CP_ACP, 0, lptStr, -1, NULL, NULL); MultiByteToWideChar(CP_ACP, 0, lptStr, -1, lpwStr, nLen);

string to BSTR

string ss = "Girish"; BSTR _bstr_home = A2BSTR(ss.c_str());

CString to BSTR

CString str = "whatever" ; BSTR resultsString = str.AllocSysString(); 

_bstr_t to CString

#include  #include  _bstr_t bsText("Hai Bayram"); CString strName; W2A(bsText, strName.GetBuffer(256), 256); strName.ReleaseBuffer(); AfxMessageBox(strName); char szFileName[256]; GetModuleFileName(NULL,szFileName,256); AfxMessageBox(szFileName);

Character arrays

Char array to integer

char MyArray[20]; int nValue; nValue = atoi(MyArray);

Char array to float

char MyArray[20]; float fValue; fValue = atof(MyArray);

Char Pointer to double

char *str = " -343.23 "; double dVal; dVal = atof( str );

Char Pointer to integer

char *str = " -343.23 "; int iVal; iVal = atoi( str );

Char Pointer to long

char *str = "99999"; long lVal; lVal = atol( str );

Char* to BSTR

char * p = "whatever"; _bstr_t bstr = p;


Float to WORD and Vice Versa

float fVar; WORD wVar; fVar = 247.346; wVar = (WORD)fVar; //Converting from float to WORD.  //The value in wVar would be 247 wVar = 247; fVar = (float)fVar; //Converting from WORD to float.  //The value in fVar would be 247.00 


LPSTR ->BSTR

BSTR bstr;
CString temp;
LPSTR lpstr;
temp = lpstr;
bstr = temp.AllocSysString();


BSTR -> int

CString str = CString(width);
this->m_width = atoi(str);


CString -> BSTR

BSTR bsFile = CString( pszFile ).AllocSysString();


CString -> char*

char * pszValue = NULL;

CString strValue = "AAA";

pszValue = (LPSTR)(LPCTSTR)strValue;


BSTR -> char*

char* BSTRtoChar(BSTR in)
{
 char* pChar = (char*)malloc(_bstr_t(in).length());
 strcpy(pChar,(char*)_bstr_t(in));
 SysFreeString(in);
 return pChar;
}


LPCTSTR -> int

int op1 = atoi((LPCTSTR) m_op1);
int op2 = atoi((LPCTSTR) m_op2);


int ->LPCTSTR

CString s;
s.Format(_T("%0.*f"),(int)nPos);


CString -> WCHAR

WCHAR       wstring[1024];
ZeroMemory(wstring, sizeof(wstring));
mbstowcs(wstring, (LPCTSTR)fullPath, fullPath.GetLength());

크리에이티브 커먼즈 라이센스
Creative Commons License
2007년 04월 04일 10시 21분 2007년 04월 04일 10시 21분

Const

1. 변수
예)
    const i = 100;
i 값 변경불가

2. 포인터형 : 기본적으로 2가지 형태가 있을 수 있음. 그외 여려형태가 가능
예1) 값은 변경 불가능하지만 주소는 변경가능한 형태
    int temp = 100, temp2 = 200;
    const int *ipConst = &temp;  // *ipConst 값 변경 불가, ipConst(주소)값은 변경가능
    // int const *ipConst = &temp;  // 이런형태로 써도 위와 같은 의미

    // *ipConst = 300;   // 불가능한 형태
    ipConst = &temp2;  // 가능한 형태

예2) 주소는 변경 불가능하지만 값은 변경가능한 형태
    int temp = 100, temp2 = 200;
    int * const iConstp = &temp;  // *iConstp 값 변경 가능, iConstp(주소)값은 변경불가

    *iConstp = 300;   // 가능한 형태
    //iConstp = &temp2;  // 불가능한 형태

주의 : const가 결합되는 위치가 값인지 주소인지에 유의


3. 참조형
예1) 직접적으로 값과 주소 모두 변경 불가능하지만 참조 원본을 통한 값변경은 가능한 경우
   int temp3 = 100, temp5 = 200;
   int const &ircVal = temp3;  
  
   //ircVal = 2000; // 컴파일 에러 발생 (const 참조는 값 변경불가)
   //ircVal = temp5;  // 주소도  변경불가
   temp3 = 9000;  // 참조 원본은 변경가능, 결과적으로 ircVal의 값도 변하게됨
   

예2) 직접적으로 값과 주소 모두 변경 가능하지만 참조가 가르키는 값은 변화가 없는경우
    int temp4 = 300, temp5 = 500;
    int & const icrVal = temp4;

    icrVal = 6000;  // 값변경 가능, 하지만 값에 변경이 안됨  
    cout << " icrVal " << icrVal << endl;  // 여전히 300이 찍힘
    icrVal = temp5; // 주소도 변경가능 역시 값에 변경이 안됨
    cout << " icrVal " << icrVal << endl;  // 여전히 300이 찍힘

4. 함수 : class의 멤버함수인 경우만 const 함수 사용가능. 해당 class의 멤버변수를 변경할수 없음.
예)
class ConstTest
{
public:
        int m_iA;

        ConstTest()
        {        m_iA = 1;           }
        int const_func1( int &a_iA,  int &a_iB) const
        {
                int a = 1;
                int b = 2;
                int c = 0;

                c = a + b;
                a_iA += 100;  
                // m_iA += 100; // 에러발생. 멤버변수는 변경 불가  
                return m_iA;
        }
};
               

5. 클레스
예)
  const CMyConstClass CC;  
 
  // 내부 멤버변수 전체를 변경불가능한 클레스,(생성자 함수만은 예외)
  // 모든 내부 멤버 함수는 기본적으로 const 함수가 되야만함.
  // 내부 함수의 지역 변수및 인자로 받은 변수는 변경가능.
크리에이티브 커먼즈 라이센스
Creative Commons License
2007년 04월 02일 01시 19분 2007년 04월 02일 01시 19분