좋은게 있어서 그대로 캡쳐~~~ ㄱㄱ씽!

 
















Hungarian Notation (헝가리안표기법)

10, 15년전 Microsoft의 개발자중 헝가리 사람의 프로그래머가 쓰던 변수 명명법.

MS내부에서 따라쓰기 시작하던 것이 점차 전세계의 프로그래머들에게 널리 퍼져 이젠 프로그램 코딩시 변수 명명의 표준적인 관례가 되었다.

그러나 실제로 현장에서 일하다 보면 헝가리안 표기법을 제대로 지키는 개발자는 그리 많지 않다. 어느정도 개발 경험을 가지고 있는 프로그래머는 물론 심지어 시중의 프로그래밍 서적에서 조차 저자마다 변수명을 개인에 따라 가지각색으로 짓고 있어서 처음 프로그램을 배우는 입문자들들이 변수 명명에 대한 기준을 제대로 잡지 못하고 있는 실정이다.

솔직히 필자도 얼마전까지 이런 변수 명명에 대한 관례를 잘 지키지 않았다. 그러나 변수 명명에 관한 표준화된 관례를 지켜주면 코드의 가독성을 높여줄 뿐 아니라 예를 들어 카운터 변수를 count라고 지을지 cnt라고 지을지 고민하지 않아도 되는 편리함을 누릴 수 있다.

--------------------------------------------------------------------------------
x_xXxxxxxx
0123456789

0 : 변수의 위치를 지정한다. g(전역변수), m(멤버변수), 없음(지역변수)
1 : 0 위치에 g 나 m 을 지정한 경우 _ 을 기술한다.
2 : 자료형의 종류를 나타낸다.
n, i : 정수형(n은 카운트 목적, i는 인덱스 목적)
l : long 형
u : 부호없는 정수형
w : 부호없는 2byte 정수형
dw : 부호없는 4byte 정수형
p : 포인터 타입
f, d : 실수형(f는 float, d는 double)
sz : char 배열(문자열 표현)
클래스 이름에 대해서는 관습적으로 자음축약형을 사용한다.
3 ~ : 변수의 의미 있는 이름을 기술하며, 3 위치는 대문자를 사용한다. 변수 이름이 너무 긴 경우 자음만을 기술한다. 예) g_nCnt

======================================================================================
:Prefix :Type :Description :Example
:b :bool :any boolean type :bool bTrue;
:c :char :character type :char cLetter;
:i :int :integer :int iCars;
:l :long :long type :long lDistance;
:u :unsigned :unsigned type
:f :float :floating point :float fPercent;
:d :double :double floating point :double dPercent;
:s :static :a static variable :static short ssChoice;
:rg :array :stands for range :float rgfTemp[16];
:p :* :any pointer :int *piAddr;
:sz :* :null terminated string of characters :char szText[16];
:pfn :* :function pointer :int (*pifnFunc1)(int x, int y);
:t :struct :a user defined type
:e :enum :variable which takes enumerated values
:E :enum :Enumerated type
:g_ :Global :Global Variable :String *g_psBuffer
:m_ :Member :class private member variable :
:k :constant formal parameter :void vFunc(const long klGalaxies)
:r :reference formal parameter :void vFunc(long &rlGalaxies)
:str :String :string class(C++) :String strName;
:prg :dynamically allocated array :char *prgGrades;
:h :handle :handle to something :hMenu
:n : :number, quantity :int nNum;
:x/y : :used as size :int xWitdth, yHeight;

======================================================================================

Example of type specific variable naming

unsigned char ucByte; :한 바이트 데이타
char cChar; :한 문자
unsigned char rgucByte[10]; :바이트 데이타 10개
char rgcChar[10]; :문자 데이터 10개
char szChar[16 +1]; :문자 16개를 저장할 수 있는 문자열 공간


:Data Type :Description
BYTE unsigned char type
WORD unsigned short type
DWORD unsigned long type

원문 : __FILE__, __FUNCTION__, __LINE__ 매크로~


printf, printk, fprintf 등등..


테스트나 디버깅 할때 어느 파일의 어느 함수의 몇번째 라인인지를 손쉽게 찍어 주는 구마..



예)


printf("파일 : %s,  함수 : %s,  라인 : %d\n", __FILE__, __FUNCTION__, __LINE__);



종종 __FUNCTION__ 에서 에러가 날수도 있는데....


그러면 대신 __func__ 를 사용하도록......

원문 : __FILE__ , __LINE__ 의 활용

#include <stdio.h>
void main() {
#line 1 "main.c"
        int i=2,j=3,k=4;
        printf("%d,%d,%d\n",i,j,k);
        printf("%s, %d\n",__FILE__,__LINE__);
        printf("%d\n",__LINE__);
#line 3897
        printf("%s, %d\n",__FILE__,__LINE__);
#line 0 "aaa.c"
        printf("%s, %d\n",__FILE__,__LINE__);
}

다음의 결과를 유추해 보세여..
시간 1분) 밑에 답을 보기 전에 꼭 먼저 생각해 보시길...
















2,3,4
main.c, 3
4
main.c, 3897
aaa.c, 0

이때 __LINE__은 현재 행의 번호를
__FILE__은 현재 파일명을 나타내는데
#line 매크로가 이값을 바꿔 줄수 있습니다.

이기법은 향후에 assert를 이용한 동적 디버깅에 많이 응용이
되니 눈여겨 봐야 합니다.
안녕하세요? 바람돌이입니다.
이번에는 간략하게 프로그래밍을 할 때의 팁을 이야기 하겠습니다.

보통 프로그램을 작성하다보면, 디버깅을 위해서 printf문을 사용할 경우가 많습니다.
또한, 배포를 한 뒤에도, 남들이 자신의 코드를 보고 디버깅을 해야하는 경우가 종종있죠.
이를 위해서 상용적인 코드에는 다음과 같은 Tip을 종종 사용하곤 합니다.

다음과 같은 코드를 header 파일에서 보신적이 있으실 겁니다.

#ifdef XXX_DEBUG
   #define print_debug(A) printf(A)
#else
   #define print_debug(A)
#endif

정확한 명칭은 다를 수 있습니다.

간단하게 살펴보면, "#ifdef"는 뒤에 전처리기명이 정의 되어있으면, 이라는 뜻입니다.
즉, XXX_DEBUG가 선언이 되어있으면, 코드 내에 있는 print_debug(A) 부분은 모두 printf(A)로 치환됩니다.
그리고, 선언이 되어있지 않으면, print_debug(A)는 모두 사라지게 되는 것이죠.

보통 우리는 함수내에 printf(A)를 직접 삽입합니다.
그리곤, 필요없는 상황이 된다면, 삭제를 하지요. 그러나, 매우 귀찮을 일이 될 것이며, 실수로 삭제를 하지 않거나 하는 상황이 발생합니다.

그러나, 위의 코딩 기법을 사용하게 되면, XXX_DEBUG를 선언하지 않는 이상 실제 코드(컴파일한 파일)엔 debugging 코드는 존재하지 않게 되지요.

게다가 만약, 다시 디버깅을 해야하는 상황이 된다면, (다 완성이 되었다고 생각했는데, 오류가 있거나, 버전업을 할 경우) XXX_DEBUG만 다시 선언하면, 곧바로 Debugging을 수행할 수 있습니다.

조금만 더 기법을 사용한다면, debugging을 level 별로도 수행 가능할 것이라 생각합니다.
그 부분은 추후 기법으로 남겨놓죠. @^-^@



전처리기에 대한 것을 더 알고 싶으시다면, #ifndef , #ifdef , #endif #pragma 등등을 검색해 보시기 바랍니다.







출처 : 낭만주의 프로그래머
원문 : 왜 코드에 주석을 달고 계십니까?

프로그래밍을 배울 무렵에는 누군가 옆에서 "코드에 주석을 달아야지" 하고 말하는 것을 한번 쯤 들어본 적이 있을 거라고 생각합니다. 혹시 코드에 왜 주석이 필요한지에 대해서 되물어 보신 적이 있나요?

코드에 주석을 다는 것은 몇 가지 이유가 있을 수 있습니다.

첫 번째는 코드의 동작에 대해서 설명을 하기 위해서 주석을 다는 경우입니다.
두 번째는 코드의 작성자라든지 소유권이라든지 또는 개정이력 등의 정보를 남기기 위한 경우입니다.
세 번째는 미래에 코드에 추가해야 할 사항이나 고쳐져야 할 내용 등을 잊지 않기 위해서 주석을 남기는 경우입니다.
네 번째는 코드의 문서화를 위한 주석을 다는 경우가 있을 것입니다.
그 밖에도 이유가 있을 수 있겠지만 이러한 범주에서 벗어나지 않을 것 같습니다.

위의 경우 중 어느 경우에 주석을 가장 많이 사용하고 계시나요? 아마도 첫 번째 경우일 것이라고 생각합니다. 물론 저도 그랬었고, 지금도 많은 경우에 첫 번째 용도로 주석을 사용하고 있습니다. 하지만 가장 주석을 달지 말아야 할 경우를 꼽는다면 역시 첫 번째 경우를 꼽겠습니다.

코드를 설명하기 위해서 주석을 다는 경우는 바꾸어서 말한다면 코드 자체로서 코드의 내용이 설명이 되지 않는다는 이야기와 같습니다. 거창한 이야기는 아닙니다. 코드를 작성할 때 변수 이름이나, 함수 이름을 조금만 신경을 써서 선택하기만 해도 코드를 설명하기 위한 주석이 필요 없어지는 경우도 많습니다.

예를 들면 for loop 를 사용할 때 loop를 돌기 위한 변수로 흔히 'i' 라는 변수명을 사용합니다. 코드가 단순하다면 상관없지만 조금만 코드가 복잡해지더라도 왜 loop 를 돌아야하는지 헷갈리는 경우가 많습니다. 더군다나 루프가 중첩이 될 때 i, j, k 와 같은 식의 변수명을 사용한다면 더욱 이해하기 어려워지게 되죠. 이런 경우에 i, j, k 대신에 왜 루프를 돌고 있는지 알려 줄 수 있는 확실한 변수명을 사용한다면 코드가 좀 더 명확해지고 별도로 주석을 달지 않더라도 무슨 동작을 하는 코드인지 확실해집니다.

코드가 이해하기 쉽고 명확하더라도 사람이 이해할 수 있는 언어로 주석을 달아서 무슨 동작을 하는 것인지 알려준다면 더 좋지 않겠는냐고 생각할 수 있습니다. 맞는 말입니다만 한 가지 반드시 지켜야하는 전제조건이 있습니다. 코드가 변경이 되었을 경우 주석도 반드시 변경이 되어야한다는 것입니다.

코드란 한번 작성하고 끝인 경우는 거의 없습니다. 일단 작성이 되면 작성한 사람이 변경을 하던지 아니면 다른 사람이 변경을 하던지 지속적으로 변경이 되는 경우가 대부분입니다. 애초에 주석을 남긴 사람이 코드를 변경할 경우 주석도 같이 변경을 하게 되는 경우가 많지만(자신의 코드에 애정이 있는 경우죠), 그렇지 않은 경우에 많은 경우 코드만 변경이 되고 주석은 변경이 되지 않는 경우가 허다합니다. 이러한 경우는 주석이 없느니만 못하게 됩니다. 코드에 주석이 달려있을 경우 코드를 처음 보는 사람은 주석을 믿게 되는 경우가 많은데 코드와 주석이 불일치한다면 코드의 동작을 오해(?)하게 되기 때문입니다. 극단적인 경우의 예로 코드를 볼 때 주석부터 지우고 본다는 분의 얘기도 들은 적이 있습니다. 주석이 코드와 일치하지 않을 경우 오히려 코드를 이해하는데 방해가 되기 때문일 겁니다.

마틴 파울러가 쓴 'Refactoring'에서는 리팩토링이 필요한 코드에서는 냄새가 나기 때문에 그 냄새를 잘 포착해서 코드를 리팩토링해야한다고 얘기하는데 그 냄새 중의 하나가 바로 코드에 주석이 필요한 경우라고 얘기했습니다. 사람이 이해할 수 없는 코드는 깔끔하게 설계되지 않은 코드이며 그러한 코드의 경우 사람이 이해하기 위해서 주석이 필요하기 때문입니다.

스티브 맥코넬의 'Code Complete' 에서는 주석부터 작성하고 코드를 작성하는 법에 대한 내용을 설명하는 부분이 있습니다. 코드의 알고리즘을 주석으로 먼저 작성을 하여 주석을 line by line 으로 코드로 대체할 수 있을 정도가 되었을 때 주석에 해당하는 코드를 작성하면 결국 코드 자체가 주석의 역할을 하여 스스로 설명하는 코드가 된다는 것입니다. 접근방법은 다르지만 결국 스스로 설명할 수 있는 코드가 훌륭한 코드라는 것에는 뜻을 같이 하는 것 같습니다.

설명을 위한 주석을 남기지 말라는 것은 아닙니다. 다만 지엽적인 코드를 설명하기 위해서 주석을 다는 것은 옳지 않다는 얘기입니다. 코드를 설명하기 위한 주석은 프로그램의 전체적인 구조라든지, 핵심 알고리즘 등을 설명하기 위한 정도가 적당한 것 같습니다. 물론 이러한 경우에도 주석 없이 설명이 가능한 것이 최선이라고 생각합니다.

마지막으로 리팩토링의 한 구절을 인용합니다.

컴퓨터가 이해할 수 있는 코드는 어느 바보나 다 짤 수 있다.
좋은 프로그래머는 사람이 이해할 수 있는 코드를 짠다.

* Question (김현수)

조교형들이 올려주신 프로그램상에서는 pidx를 클래스내에서
 
TelPhoneBook() : pidx(0)            

위와 같이 변수를 함수처럼 사용한 부분이 있는데 int pidx = 0; 과 비교해서

어떤 차이가 있는지 그리고 위와같은 사용은 c에서는 본적이 없는데

약간의 문법적인 내용까지 알려주시면 감사하겠습니다...

그럼 수고하십시오~~~~^^;


* Answer (박성환)

저희 조교들도 이번기회에 정확히 배우고자

교수님께 직접 문의를 드렸습니다.

알고보니, 저희가 모르는 심오한 세계가 또 있더군요...

(정말, 배움의 길은 끝이 없나 봅니다... 에궁... 어려버~)

생성자에

class A
{
   C c;
   A(C c1) : c(c1)
  {
  }
}

을 A로 하고,

class B
{
  C c;
  B(C c1)
  {
     c = c1;
  }
}

을 B라고 하면, 실제로 엄청난 차이가 있었습니다.

머, 위의 예 보다는 멤버변수가 또 다른 Class일 때 특히 그런데요,

실제로 Compile을 하게 되면, A와 같은 경우에는 Machine Code가 확연히 줄어들게 됩니다.

즉 C라는 Class를 인자로 받아 대입하게 되면, B와 같은 경우에는

복사생성자가 호출이 됩니다.

실제로 C 객체가 생성이 된 뒤 B class의 C class부분에 복사생성자로 초기화가 진행됩니다. (Memory가 한번 더 할당이 된다는 걸 아시겠죠?)

하지만, A의 경우 A class의 생성자가 호출이 되면, A Class의 C Class부분은 곧바고 C Class의 생성자로 초기화를 하게 됩니다.
(Memory가 순수 A class 만큼 할당이 된다는 걸 아시겠죠?)

때문에 두 코드에는 심오한 차이가 존재했습니다.

위와 같은 경우에는 Memory에도 차이가 나겠지만,

중요한 것은 Machine Code의 양이 줄어든다는 것입니다.

복사생성자가 호출되지 않는 (기본 Type 등등) 경우에는 실제 Memory는 별 차이가 없게 되지만,

Machine Code는 차이가 나게 됩니다.



최근에는 Compiler가 급속한 성장을 하여 기본 type에는 큰 차이를 보이지 않습니다. Compiler에게 "-o" 옵션을 주면 최적화를 진행하게 되는데,

이때 기본 type같은 경우 B경우를 A와 같은 처리를 하여 Machine code를 알아서 줄여주는등, 알아서 변환을 하게 됩니다.



머, 사용하는 입장에서는 큰차이가 없지만, 중요하게 알아두시면 좋을 것 같네요.

왜? C class의 크기가 대용량의 크기를 가진다고 가정해 봅시다...

B와 같이 사용하면... 우리가 모르는 사이에... Program이 죽어버릴지둥...

@^-^@

이런 지식하나하나가 학원에서는 절대 배울 수 없는 지식이겠죠?

잘 알아두시길 바랍니다~

그리고, 현수에게 고맙네요~ 덕분에 좋은것을 알게 되어서~ 쌩유~

@^-^@
■ Requirements






■ Functions



▶ size_t strlen (const char *string)

Parameters

string

Null이 아닌 문자열.

Return Value

string문자열 중에 Null 문자를 제외한 문자의 개수를 반환한다.

Error에 대한 반환값은 정의 되어 있지 않다.

Remarks

이 함수는 string문자열 중에 Null 값을 제외한 문자의 개수를 반환한다.

Security Note

이 함수는 잠재적으로 buffer overrun 문제가 발생할 수 있다.

Buffer overrun은 적절하지 않은 수준의 권한이 되는, System 공격 방법중 하나이다.

더 자세한 사항은 Avoiding Buffer Overruns 을 참조하라.

추가 참조

char string[32] = "hello, world";



int size1 = sizeof (string);

int size2 = strlen (string);



printf("sizeof(string) = %d ,strlen(string) = %d\n");

result:

sizeof(string) = 32,strlen(string) = 12





▶ char* strcpy (char *strDestination, const char *strSource)

Parameters

strDestination

문자열이 복사될 목적 문자열 포인터

strSource

Null로 끝나는 원본 문자열


이 함수는 복사된 문자열 포인터를 반환한다.

Error에 대한 반환값은 정의 되어 있지 않다.

Remarks

strcpy 함수는 Null 문자로 끝나는 strSource 문자열을 strDestination로 복사한다.

원본과 목적 문자열이 겹쳐진다면 strcpy는 오작동 할 수도 있다.

Security Note

strcpy함수는 strSource를 복사하기 전에 strDestination의 공간을 확인하지 않아

잠재적으로 Buffer overrun을 발생시킬 수 있다. 대신 strncpy을 사용하라.



▶ char* strncpy (char *strDest, const char *strSource, size_t count )

Parameters

strDest

문자열이 복사될 목적 문자열 포인터

strSource

원본 문자열

count

복사될 문자 개수

Return Value

strDest을 반환한다. Error를 위한 반환값은 정의 되지 않았다.



strncpy 함수는 strSource의 처음부터 count개의 문자를 strDest로 복사하고,

strDest를 반환한다.

만약 count가 strSource의 길이보다 작거나 같다면,

복사된 문자열에 자동으로 Null문자를 붙여주지 않는다.

만약 count가 strSource의 길이보다 크다면,

목적 문자열은 count길이 뒤에 null문자를 붙여준다.

원본과 목적 문자열이 겹쳐진다면 strncpy는 오작동 할 수도 있다.


Security Note

strncpy는 strDest에 충분한 공간이 남아있는지 검사하지 않는다.

그럼으로 buffer overrun 발생의 잠재적 가능성이 있다.

count가 복사될 문자의 개수를 제한한다는 것을 잊지 마라.

그것은 strDest의 크기를 제한하는 것이 아니다.



▶ char* strdup (const char *strSource)

Parameter

strSource

Null로 끝나는 원본 문자열

Libraries

C run-time libraries의 모든 버전.

Return Value

이 함수는 복사된 문자열의 저장공간을 리턴하거나,

새로 할당할 수 없을땐 Null을 반환한다.

Remarks

strdup함수는 strSource의 복사를 위해 저장공간을 할당하려고 malloc함수를

호출한다. 그리고 strSource를 할당한 저장공간에 복사한다.


▶ char* strcat (char *strDestination, const char *strSource)

Parameters

strDestination

Null로 끝나는 목적 문자열

strSource

Null로 끝나는 원본 문자열

Libraries

C run-time libraries의 모든 버전.

Return Value

이 함수는 strDestination 를 반환한다. Error에 대한 반환값은 정의 되어 있지 않다.

Remarks

strcat 함수는 strDestination 문자열에 strSource 문자열을 붙여주고,

Null 문자로 목적 문자열을 종료 시켜준다.

목적 문자열의 Null 종료문자는 원본 문자열의 첫 문자에 의해 덮어 써진다.

문자열을 복사하거나 붙일때에는 overflow를 검사하지 않는다.

원본 문자열과 목적 문자열이 겹칠때에는 strcat 함수는 오작동 할 수 있다.

Security Remarks

첫번째 인자인 strDestination 은 반드시 strDestination 와 strSource 문자열,

그리고 Null 문자인 '\0'를 합친 크기보다 충분히 커야만 한다.

그렇지 않다면, buffer overrun이 발생할 수 있다.

만약 접근영역을 침범하면 서비스거부공격이 일어날 수 있고,

최악의 상황에서는 공격자가 당신의 프로세스에 실행가능한 코드를 삽입할 수 있다.

만약 strDestination 이 stack-based buffer였다면 특히 그렇다.

strncat 나 wcsncat 함수를 사용하여라.



▶ char* strncat (char *strDest, const char *strSource, size_t count)

Parameters

strDest

Null로 끝나는 목적 문자열

strSource

Null로 끝나는 원본 문자열

count

붙여질 문자 개수

Libraries

C run-time libraries의 모든 버전.

Return Value

이 함수는 strDestination 를 반환한다. Error에 대한 반환값은 정의 되어 있지 않다.

Remarks

strncat 함수는 기껏해야 strSource 문자열의 처음부터 count 개수만큼의 문자를

strDest 문자열에 붙인다.

목적 문자열의 Null 종료문자는 원본 문자열의 첫 문자에 의해 덮어 써진다.

만약 count 개수만큼 붙이기 전에 strSource 안에 Null 문자가 있다면,

strncat 함수는 Null 문자를 포함해 strSource 의 모든 문자를 붙인다.

만약 count 가 strSource문자열의 길이보다 크다면, strSource 문자열의 길이가

count 대신 쓰여진다. 결과 문자열은 Null문자로 끝나게 된다.

원본 문자열과 목적 문자열이 겹칠때에는 strncat 함수는 오작동 할 수 있다.

Security Remarks

첫번째 인자인 strDest은 반드시 strDest와 strSource 문자열,

그리고 Null 문자인 '\0'를 합친 크기보다 충분히 커야만 한다.

그렇지 않다면, buffer overrun이 발생할 수 있다.

만약 접근영역을 침범하면 서비스거부공격이 일어날 수 있고,

최악의 상황에서는 공격자가 당신의 프로세스에 실행가능한 코드를 삽입할 수 있다.

만약 strDestination 이 stack-based buffer였다면 특히 그렇다.

마지막 인자인 count는 strDest의 크기가 이나라

strDest중에 복사될 문자 개수임을 명심해라.




특정 site들에서 참고하여 보기 좋게 정리하며 제 생각을 추가한 것입니다

오래전 자료라서 어느 site인지는 기억이 나질 않네요.

+ Recent posts