반응형

개요

실제로는 독립적인 코드 조각을 의미하기도 한다. 프로그래밍 언어에서 특정한 동작을 독립적으로 정의하고 해당 코드를 호출하기 위해 만들어진 개념이다. C 이후에 만들어진 대부분의 프로그래밍 언어에는 존재한다.

코드를 작성할 때 마다 처음부터 작성하는 방법도 있지만, 누군가가 작성해 놓은 코드를 사용 할 경우 함수 형태로 사용하거나 작성하기도 한다.

정의와 호출

어떠한 동작을 할 것인지 def 키워드로 함수를 정의한다. 이미 정의 되어 있는 함수는 함수 이름으로 호출하여 사용한다. 키워드 def는 define에서 따온 것을 추측할 수 있다. 함수명 뒤에는 소괄호로 열고 닫고 마지막으로 코드블록의 시작을 알리는 콜론을 해준을 해준 다음에 들여쓰기로 함수에 해당하는 코드를 작성할 수 있다.

def hello():
    print("hello world")

hello()
# hello world

위의 예제 기준으로 설명하면 hello 는 함수명이 된다. 처음 입문자가 헷깔리는 것이 함수를 정의할 때는 코드가 동작하지 않는다. 실제로 동작하는 것은 함수가 호출 될 때이다. 함수가 호출될 때는 소괄호를 열고 닫아야 한다.

입력 파라미터

입력 파라미터를 입력 인자라고 말하기도 한다(반만 영어인 용어). 함수를 정의할 때 동작시 값을 입력 받을 수 있도록 할 수 있다. 앞의 함수의 예시는 입력 파라미터가 없기 때문에 공란으로 둔 것이다. 입력 파라미터가 있는 함수를 정의하기 위해서는 함수명의 뒤에 오는 소괄호에 함수내에서 변수로 사용할 값을 넣어주면 된다. 만약 입력 파라미터가 2개 정의 되어 있는데, 함수 호출시 입력 파라미터의 수가 맞지 않으면 에러를 발생하고 함수의 코드블록이 실행되지 않는다.

def add(a, b):
	print(a + b)

add(1, 2)
# 3
add(1)
# Error

함수를 정의할 때 정의된 입력 파라미터를 반드시 전부 사용해야 한다는 의무는 없다. 하지만 호출할 때는 default 값이 정해져 있는 것이 아니라면 반드시 정의된 입력 파라미터의 수가 맞아야 한다.

우리가 이전 부터 종종 사용한 print()도 사실 함수이다.

default 값

함수의 입력 파라미터에 대해서 default 값을 정의 할 수 있다. default 값은 해당 입력 파라미터가 없는 경우 미리 정의 되어 있는 상수로 입력 파라미터 값을 사용한다.

default 값이 있는 입력 파라미터는 default 값이 없는 입력 파라미터의 오른쪽에 정의 되어야 한다. 참고로 입력 파라미터가 있는 함수의 호출 과정은 마치 중학교 수학과정의 수학의 함수기호를 사용하는 것과 비슷하다.

def add(a, b = 1):
    print(a + b)

add(1, 2)
# 3

add(1)
# 2

add()
# Error

def diff(a=10, b):
    print(a + b)
# Error

반환

반환이라는 명칭은 C 에서 return 키워드를 통해서 함수에 있는 코드블록의 실행 결과를 호출한 위치에 값을 주는 개념으로 사용되었다. 이는 다른 언어에서도 대부분 동일하게 동작하고 파이썬도 마찬가지다. 이는 함수를 통해서 어떠한 결과를 얻었다는 느낌으로 사용된다.

반환되는 값을 있을 수도 있고 없을 수 도 있다. 함수의 코드블록이 전부 실행되면, 함수 코드블록내에서만 사용한 변수들은 다른 코드블록(보통 외부)에서 접근을 할 수 없다. 하지만 반환 값(리턴되는 값)은 함수 코드블록 밖으로 내보내는 것이고, 그 결과 코드상 함수가 호출된 위치에 반환된 값이 있는 것과 같은 결과가 된다.

def add(a, b):
    return a + b

result = add(1, 2)
# result = 3

result + 4 == add(3, 4)
# True

파이썬에서 독특한 문법으로 반환되는 값이 복수가 될 수 있다. 이렇게 복수로 반환 할 경우 기본적으로 튜플(Tuple)로 묶여서 반환 된다(여기서 독특하다는 이유는 대부분 언어에서는 이렇게 반환되지 않기 때문이다).

함수의 반환 값을 바로 대입할 때 반환 값의 수와 동일한 개수의 변수를 정의 하면 튜플의 원소가 각각 변수에 대입된다.

def minMax(a, b, c):
    minVal = min(a, b, c)
    maxVal = max(a, b, c)
    return minVal, maxVal

results = minMax(1, 2, 3)
print("results:", results)
# results == (1, 3)

minVal, maxVal = minMax(1, 2, 3)
print("(min, max):", minVal, maxVal)
# minVal == 1
# maxVal == 3

함수 내에서 return 키워드가 오게 되면, 함수는 해당 값을 반환하고 함수의 실행을 종료한다. 만약 함수내에 반복문을 실행중이라도 return 키워드를 만나면 반복문의 코드 블록을 포함해서 함수가 종료된다.

words = ["hello", "papa", "its", "me"]
def find(words, keyword):
    index = 0
    for itWord in words:
        if itWord == keyword:
            return index
        index += 1
    return -1

index = find(words, "papa")
print("index:", index)
# index == 1

index = find(words, "what")
print("index:", index)
# index == -1

만약 함수 정의에서 return 키워드를 사용하지 않으면 반환값이 없게 된다. 반환값이 없는 함수를 호출하여 변수에 대입을 하면 None이 대입됨을 알 수 있다. 정확히는 반환값이 없는 것이 아니라 default로 None이 반환되고 있는 것이다.

def diff(a, b):
    print(a - b)

result = diff(1, 2)
print("result:", result)
# result == None

내장 함수

함수 문법에 대한 기초를 이해하고 나면, 한가지 거슬리는 것이 있을 것이다. 바로 화면에 출력하는 print()라던가 예시에 있는 min(), max() 같은 것말이다. 이는 python에서 미리 정의가 되어 있는 함수들이다.

별도로 정의 하지 않았지만, python 자체적으로 바로 사용하는 함수들을 내장 함수라고 부른다. 내장 함수들은 자주 사용되며 코드의 질을 높이는 유용한 것들이 많다. 이에 대해서는 나중에 다시 다루도록 하자

글로벌 변수

함수 등 특정 블록이 아닌 가장 밖에 있는 변수를 글로벌 변수 혹은 전역 변수라 부른다. 함수에서 입력 파라미터 외에 글로벌 변수에 대해서 접근이 가능하다. 하지만, 함수에서 해당 값을 수정하기 위해서는 global 키워드를 사용해야 한다.

gVal = 1

def aFunc1():
    print(gVal)

def aFunc2(a1):
    gVal = a1

def aFunc3(a1):
    global gVal
    gVal = a1

aFunc1()
# 1

aFunc2(3)
# Error

aFunc3(3)
aFunc1()
# 3

특별한 경우를 제외하고 글로벌 변수를 수정하는 것은 바람직하지 않다. 이는 프로그램이 복잡하게 되었을 경우 해당 변수를 어디서 참조하여 영향을 받을지 알 수 없기 때문이다. 이 때문에 별도의 global 키워드를 사용해서 global 변수를 수정하도록 설계되었고, 이를 통해 함수의 코드블록 내에서 글로벌 변수를 수정하는지를 확인하기 쉬워졌다.

반응형

'Python > 배경이 있는 파이썬' 카테고리의 다른 글

반복문(while, for)  (0) 2024.05.11
코드 블록, 조건문(if)  (1) 2024.05.01
불(bool)과 연산  (0) 2024.04.29
딕셔너리(dict)  (0) 2024.04.29
튜플(Tuple)  (1) 2024.04.27
반응형

C에서 간단한 dll을 만들어 C++에서 사용하기


 C에서는 MVC++의 C++와 달리 "#pragma" 매크로를 지원하지 않는다. 하지만, C에서는 전통적으로 다른 파일에서 사용할 수 있도록 하는 "extern"을 키워드가 있다.


 다음은 MSDN의 간단한 예시를 조금 수정했다. 


내보내기 예시)

 MSDN의 예제의 경우 __declspec( dllexport )로 작성된 부분이 __declspec( dllimport )로 작성이 되어 있는데, MSDN측 오타로 생각된다.

// MyCFuncs.h
#ifdef __cplusplus
extern "C" {  // only need to export C interface if
                  // used by C++ source code
#endif

__declspec( dllexport ) void Hello(void);

#ifdef __cplusplus
}
#endif


// MyCFuncs.c
#include "MyCFuncs.h"
#include <stdio.h>

void Hello(void)
{
    puts("Hello world");
}


dll 들여오기(Import) 공통 작업

 C++의 dll 파일을 링크하는 것과 비슷한 준비 작업이 필요하다. 실행 프로그램의 프로젝트를 생성한다. 여기서는 "Windows 데스크탑"의 빈프로젝트로 생성한다.

해당 프로젝트 폴더로 내보내는 예시에서 만든 lib파일과 헤더파일을 복사한다.

"솔루션 탐색기"에서 "헤더 파일"항목에 마우스 우클릭을 한뒤 "추가 -> 기존항목"에서 복사한 헤더파일을 추가한다.



들여오기 예시1)

 "솔루션 탐색기"에서 해당 프로젝트 명을 우클릭하여 "프로젝트 속성" 창을 연다.

프로젝트 속성의 "링크 -> 일반"의 "추가 라이브러리 디렉터리" 항목에 lib 파일이 있는 폴더 경로를 추가 입력해준다.

프로젝트 속성의 "링크 -> 입력"의 "추가 종속성"항목에 lib파일 이름과 확장자 명을 추가 입력을 한다.

아래의 소스코드를 작성한다.

// MyCFuncsRef.cpp
#include "MyCFuncs.h"

int main(const int & argc, const char * argv[])
{
    Hello();
    return 0;
}


컴파일 후 프로그램을 실행할때에는 실행하는 폴더안에 해당 dll 파일이 반드시 있어야한다.



들여오기 예시2)

아래와 같이 매크로 "#pragma comment(lib, " ./MyCfuncs.lib")를 선언부 입력을 해준다.


// MyCFuncsRef.cpp
#pragma comment(lib, "./MyCFuncs.lib")

#include "MyCFuncs.h"

int main(const int & argc, const char * argv[])
{
    Hello();
    return 0;
}


컴파일 후 실행파일이 있는 폴더 안에 해당 dll 파일이 있어야 정상적으로 실행된다.



정리

 C의 경우 클래스와 같은 자료형을 지원하지 않기 때문에 단지 헤더파일 부분만 주의 깊게 작성하면 된다. 다만, C++에서는 해당 헤더파일이 C++에서 사용된다는 것을 알리기 위하여 매크로 변수 __cplusplus를 이용 하여 extern "c" { 항목을 활성 혹은 비활성 한다는 점을 기억하자.


 dll참조 함수의 성능을 높이기 위해 포인터로 함수 주소를 가져와서 호출하는 방법도 있는데, 이부분은 추가로 더 조사를 해봐야 될것 같다.



참고자료

MSDN C 함수를 ~ 내보내기




반응형

+ Recent posts