본문 바로가기

Studying/Computer Programs

C/C++ 에서 함수를 매개변수로 사용하기

함수 포인터를 이용한 구현

일반적으로 C언어나 C++ 에서 사용하는 함수의 경우, 인자(매개변수) 혹은 파라미터로 변수를 받아갑니다. 이 값들을 가지고 정의된 기능을 수행하게 되죠. 하지만 프로그램을 만들다 보면 함수 자체를 다른 함수의 매개변수로 하는 방식이 유용할 때가 있습니다. 함수의 포인터를 다른 함수의 인자로 설정함으로써 이를 구현할 수 있으며, 이 때 함수의 파라미터 및 리턴값을 정확하게 명시해야 합니다.

 

반응형

 

Hello World! 코드를 약간 바꿔서 이를 사용해 봅시다.

 

#include<stdio.h>

void let_us_say(void (*func_message)());
void greetings();
void goodbye();

int main(int argc, char *argv[]) {
    // function pointer
    void (*ptr_func)();

    fprintf(stdout, "\n");

    // the pointer is now to greetings()
    ptr_func = &greetings;
    let_us_say(ptr_func);

    // the pointer is now to goodbye()
    ptr_func = &goodbye;
    let_us_say(ptr_func);

    return 0;
}

void let_us_say(void (*func_message)()) {
    fprintf(stdout, "Let's say : ");
    (*func_message)();
    fprintf(stdout, "\n");
}

void greetings() {
    fprintf(stdout, "Hello World!\n");
}

void goodbye() {
    fprintf(stdout, "Bye Bye ~\n");
}

 

위의 프로그램에서 main 함수는 let_us_say 라는 함수를 호출하고 있는데요. 이 함수는 파라미터와 리턴값이 없는 함수를 매개변수로 받고 있습니다. main 함수 위에 위치한 프로토타입에 따르면 let_us_say 라는 함수 자체도 리턴값이 없죠. main 함수 바로 밑에는 let_us_say 함수에 대한 정의가 있습니다.

주의할 점은 func_message 는 함수의 포인터이므로, 실제 함수를 호출하기 위해서는 메모리 주소에 연동된 값을 불러오는 * 연산자를 앞에 붙여줘야 한다는 것입니다.  추가적으로 let_us_say 함수의 매개변수로 들어갈 greetingsgoodbye 함수를 정의해 줍니다. 이 코드를 실행시켜 보면 다음과 같은 결과를 얻을 수 있습니다.

 

execution of a program to print HelloWorld by means of function pointers

 

정적분이나 미분방정식 등의 수치적인 해를 구하는 프로그램 등에 함수의 포인터를 유용하게 활용할 수 있습니다. 구체적인 예시들은 다음 포스팅들에 소개되어 있습니다.

 

Runge-Kutta 방법을 이용하여 초기조건이 주어진 연립 상미분 방정식을 풀 수 있습니다.

 

 

C/C++ Runge-Kutta 방법으로 알아보는 진자운동

진자운동의 개요 이번 포스팅에서는 천장에 매달린 진자의 운동에 대한 썰을 수치해석과 함께 한번 풀어볼까 합니다. 중력이 복원력으로 작용하는 왕복운동은 고등학교 물리 교과서에도 등장

swstar.tistory.com

 

 

C/C++ Runge-Kutta 방법으로 알아보는 인구역학

목차 로지스틱 방정식 확장된 가설 : 어른과 어린이 확장된 가설 : 인간과 삼림 인터넷을 돌아다니다가 우연히 인구역학 (population dynamics) 및 이를 위한 수학적 모형에 대한 설명을 위키 페이지에

swstar.tistory.com

 

반복-이완 계산법을 통해 경계조건이 주어진 연립 상미분 방정식을 풀 수 있습니다.

 

 

C/C++ 반복-이완 계산법으로 알아보는 비행경로

이번 포스팅에서는 구면 상에 있는 두 지점 사이의 최단 경로를 위도와 경도에 대한 함수로 구한 다음, 출발지와 목적지 사이의 비행기 항로를 결정하는 방법에 대해 알아봅시다. 수치해석 방법

swstar.tistory.com

 

GSL 라이브러리를 이용한 정적분에도 함수의 포인터가 들어갑니다.

 

GSL : C/C++ 수치해석 라이브러리

이번 포스팅에서는 이공계 분야의 수치해석에서 널리 쓰이는 GSL라이브러리에 대해 써 볼까 합니다. GSL은 GNU Scientific Library의 약자로서, 과학 및 공학 분야의 수치해석에 유용한 여러가지 함수들

swstar.tistory.com

 

예시

급수와 오일러 상수

첫번째 예시로서, 급수 계산 프로그램을 소개할까 합니다. 수열의 각 항을 리턴하는 함수를 정의하고, 이 함수의 포인터를 인자로 받아서 유한급수를 계산하는 프로그램을 만들어볼텐데요. 여기서는 자연지수 함수의 밑이 되는 오일러 상수 (Euler's number)를 한번 계산해 보겠습니다. 자연지수 함수가 어떻게 정의되는지, 그리고 이로부터 오일러 상수를 어떻게 계산할 수 있는지에 대해서는 다음 포스팅에 소개되어 있습니다.

 

 

수학 상식 : 지수함수와 로그함수

이번에는 자연과학 및 공학 분야에서 중요하게 다뤄지는 오일러 상수 (Euler number 혹은 자연 상수)와 지수함수 (exponential function)에 대해 알아봅시다. 크기나 숫자 등이 폭발적으로 증가하는 현상

swstar.tistory.com

 

C언어 코드입니다.

 

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

/* n_min 에서 n_max 까지의 유한급수를
 * 계산하는 함수입니다.
 * 더하고자 하는 수열의 각 항을 정의하는
 * 함수의 포인터도 인자로 받고 있습니다. */
double sum_series(long int n_min,
                  long int n_max,
        double (*ptr_term)(long int));

/* 오일러 상수를 구하기 위한 무한급수의
 * 각 항을 정의하는 함수입니다. */
double get_term_exp(long int n);

// 메인 함수
int main(int argc, char *argv[]) {
    /* 함수 포인터 변수를 선언하고
     * 이 포인터는 get_term_exp 함수를
     * 가리킵니다. */
    double (*ptr_func)(long int);
    ptr_func = &get_term_exp;

    long int n_min = 0;
    long int n_max = 20;
    // 유한급수로 오일러 상수의 근사값 계산
    double e_euler =
        sum_series(n_min, n_max, ptr_func);

    /* 오일러 상수의 근사값을 출력하고
     * C 수학 함수 라이브러리의 값과 비교 */
    fprintf(stdout,
        "e from finite series\n");
    fprintf(stdout,
        "  > e = %.16f\n", e_euler);
    fprintf(stdout,
        "e from C math library\n");
    fprintf(stdout,
        "  > e = %.16f\n", M_E);

    return 0;
}

double sum_series(long int n_min,
                  long int n_max,
        double (*ptr_term)(long int)) {
    double sum = 0.;

    long int i;
    for (i = n_min; i <= n_max; i++) {
        sum += (*ptr_term)(i);
    }

    return sum;
}

double get_term_exp(long int n) {
    if (n < 0) {
        return 0.;
    }

    double term = 1.;

    long int i;
    for (i = 1; i <= n; i++) {
        double factor_now = 1. / (double)i;
        term = term * factor_now;
    }

    return term;
}

 

이 프로그램의 핵심 요소는 유한급수의 값을 계산하는 sum_series 함수입니다. 이 함수는 더하고자 하는 수열의 범위와 함께, 수열의 형태를 정의한 함수의 포인터를 매개변수로 받고 있습니다. 수열의 각 항을 정의하는 함수는 정수형 변수를 인자로 받아서 실수형 변수를 리턴하는 방식을 상정하고 있으므로, main 함수에서 함수 포인터 변수 ptr_func 를 선언할 때도 매개변수와 리턴값의 자료형들을 맞춰야 하겠죠.

 

여기서는 오일러 상수를 계산하고자 하기 때문에, 그에 해당하는 수열을 정의한 함수 get_term_exp 가 있습니다. 유한급수를 구하는 sum_series 함수가 get_term_exp 함수의 포인터를 인자로 받아가면, 오일러 상수의 근사값을 계산할 수 있게 되겠습니다. 프로그램을 실행하면 다음과 같은 결과를 볼 수 있습니다.

 

execution of a program to evaluate Euler's number

 

푸리에 변환

지금까지는 설명을 위해 간단한 코드를 예로 들었습니다만, 이제는 좀 더 실용적인 걸 해 봅시다. 저번 포스팅에서 고속 푸리에 변환 라이브러리인 FFTW에 대해 간략하게 소개를 했었습니다. 그리고 가우스함수의 푸리에 변환을 위한 예제 코드도 같이 첨부를 했죠.

 

 

FFTW : 고속 푸리에 변환 라이브러리

현재 진행중인 연구에서 사용중인 C언어 푸리에 변환 라이브러리인 FFTW에 대해 간략히 포스팅해볼까 합니다. FFTW는 Fastest Fourier Transform in the West 의 약자인데요. 저 같은 토종 아시안은 이해 못하

swstar.tistory.com

 

위 포스팅에서는 모든 함수를 하나의 소스 파일 안에 넣고, 푸리에 변환을 main 함수에서 진행했었는데요. 이번에는 새로운 객체를 도입하고 변환대상이 되는 함수를 인자로 전달하는 방식으로 코드를 재구성해 볼 예정입니다. 이렇게 하면 사용하기에도 더 편리하고, 코드의 가독성도 높아지는 효과가 있으리라 기대해 봅니다.

FFTransformer.h [다운로드]

 

더보기
#ifndef FFTRANSFORMER_H
#define FFTRANSFORMER_H

#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<fftw3.h>

typedef struct PtrFuncFFT {
    double (* re)(double, void *);
    double (* im)(double, void *);
    void *param;
} PtrFuncFFT;

class FFTransformer {
  private :

    int nbin_q_;
    double q_min_;
    double q_max_;
    double delta_q_;
    double *qbin_;
    double **func_q_;
    int nbin_x_;

    double delta_x_;
    double x_min_;
    double x_max_;
    double *xbin_;
    double **func_x_;

    bool initialized_;

    bool direction_fft_;

    /* the input array
     * containing a function to be tranformed */
    fftw_complex *array_fft_ini_;
    /* the output array
     * containing the outcome */
    fftw_complex *array_fft_fin_;

    // declare and initialize FFT transformer
    fftw_plan fft_plan_;

  public :

    FFTransformer() {
        initialized_ = false;
    };
    ~FFTransformer() {
        free_array();
    };

    void free_array() {
        if (!initialized_) {
            return;
        }

        // deallocate the FFTW stuffs
        fftw_destroy_plan(fft_plan_);
        fftw_free(array_fft_ini_);
        fftw_free(array_fft_fin_);

        for (int iq = 0; iq <= nbin_q_; iq++) {
            delete [] func_q_[iq];
        }
        delete [] func_q_;
        delete [] qbin_;

        for (int ix = 0; ix <= nbin_x_; ix++) {
            delete [] func_x_[ix];
        }
        delete [] func_x_;
        delete [] xbin_;

        initialized_ = false;
    }

    bool init(double q_min_in, double q_max_in,
              double delta_q_in, bool direction_fft_in);

    bool next(PtrFuncFFT ptr_func_in);

    void get_array_ini(std::vector<double> &q_out,
                       std::vector<double> &func_re_out,
                       std::vector<double> &func_im_out);
    void get_array_fin(std::vector<double> &x_out,
                       std::vector<double> &func_re_out,
                       std::vector<double> &func_im_out);

    void write(const char *filename);
};

#endif


헤더 파일에서는 FFTransformer 클래스의 각종 변수와 함수들의 프로토타입이 선언되어 있습니다. 변환대상 및 변환된 함수들에 대한 정보를 저장하기 위한 배열 및 FFTW 실행을 위한 클래스 변수들을 포함하고 있죠. init 함수를 이용해서 함수들의 정의역과 격자 간격을 입력하고, 푸리에 변환이 정방향인지 역방향인지를 지정한다음 객체를 초기화할 수 있습니다.

함수와 파라미터의 포인터들로 이루어진 구조체 PtrFuncFFT 가 새롭게 정의되어 있는데요. 이는 복소수함수의 실수(re) 및 허수(im)부분의 포인터를 멤버로 가지고 있습니다. 또한 파라미터의 포인터 param 도 있는데, 함수의 특징을 결정짓는 각종 파라미터 변수들의 포인터입니다. 여기서 예시로 든 가우스 함수의 경우 평균값 및 폭을 구조체로 정의한 다음, 그 구조체의 포인터로 설정하는 게 가능합니다.

그다음으로 눈여겨봐야 할 것은 next 라는 멤버함수의 프로토타입입니다. 변환대상이 되는 복소수함수의 포인터 구조체 (PtrFuncFFT)를 매개변수로 받은 다음 푸리에 변환을 실행하는 함수죠. 마지막으로 결과물을 파일에 출력하기 위한 write 함수가 있습니다.

FFTransformer.cpp [다운로드]

 

더보기
#include"FFTransformer.h"

bool FFTransformer::init(double q_min_in, double q_max_in,
                         double delta_q_in, bool direction_fft_in) {
    free_array();

    q_min_ = q_min_in;
    q_max_ = q_max_in;
    delta_q_ = delta_q_in;
    direction_fft_ = direction_fft_in;

    nbin_q_ = (int)floor((q_max_ - q_min_) / delta_q_ + 1e-8);
    if (nbin_q_ % 2 == 1) {
        nbin_q_ += 1;
    }
    delta_q_ = (q_max_ - q_min_) / (double)nbin_q_;

    qbin_ = new double [nbin_q_ + 1];
    func_q_ = new double *[nbin_q_ + 1];
    for (int iq = 0; iq <= nbin_q_; iq++) {
        qbin_[iq] = q_min_ + delta_q_ * (double)iq;
        func_q_[iq] = new double [2];
        func_q_[iq][0] = 0.;  // real part
        func_q_[iq][1] = 0.;  // imaginary part
    }

    nbin_x_ = nbin_q_;

    /* lattice spacing in the x-space,
     * which is depending on one in the q-space */
    delta_x_ = 2. * M_PI / (delta_q_ * (double)nbin_q_);
    x_min_ = -0.5 * delta_x_ * (double)nbin_x_;
    x_max_ = 0.5 * delta_x_ * (double)nbin_x_;

    xbin_ = new double [nbin_x_ + 1];
    func_x_ = new double *[nbin_x_ + 1];
    for (int ix = 0; ix <= nbin_x_; ix++) {
        xbin_[ix] = x_min_ + delta_x_ * (double)ix;
        func_x_[ix] = new double [2];
        func_x_[ix][0] = 0.;  // real part
        func_x_[ix][1] = 0.;  // imaginary part
    }

    array_fft_ini_ =
        (fftw_complex *)fftw_malloc(nbin_q_ * sizeof(fftw_complex));
    array_fft_fin_ =
        (fftw_complex *)fftw_malloc(nbin_x_ * sizeof(fftw_complex));

    if (direction_fft_) {
        fft_plan_ =
            fftw_plan_dft_1d(nbin_q_,
                array_fft_ini_, array_fft_fin_,
                FFTW_FORWARD, FFTW_MEASURE);
    } else {
        fft_plan_ =
            fftw_plan_dft_1d(nbin_q_,
                array_fft_ini_, array_fft_fin_,
                FFTW_BACKWARD, FFTW_MEASURE);
    }

    initialized_ = true;
    return true;
}

bool FFTransformer::next(PtrFuncFFT ptr_func_in) {
    if (!initialized_) {
        return false;
    }

    void *ptr_param = ptr_func_in.param;
    for (int iq = 0; iq <= nbin_q_; iq++) {
        // real part
        func_q_[iq][0] =
            (*ptr_func_in.re)(qbin_[iq], ptr_param);
        // imaginary part
        func_q_[iq][1] =
            (*ptr_func_in.im)(qbin_[iq], ptr_param);
    }

    // define the input array
    for (int iq = 0; iq < nbin_q_; iq++) {
        double factor_in[2];
        factor_in[0] = cos(x_min_ * delta_q_ * (double)iq);
        if (direction_fft_) {
            factor_in[1] = -sin(x_min_ * delta_q_ * (double)iq);
        } else {
            factor_in[1] = sin(x_min_ * delta_q_ * (double)iq);
        }
        array_fft_ini_[iq][0] =
            func_q_[iq][0] * factor_in[0] -
            func_q_[iq][1] * factor_in[1];  // real part
        array_fft_ini_[iq][1] =
            func_q_[iq][1] * factor_in[0] +
            func_q_[iq][0] * factor_in[1];  // imaginary part
    }

    /* perform FFTW to take the input array
     * and compute the output array */
    fftw_execute(fft_plan_);

    double factor_measure;
    if (direction_fft_) {
        factor_measure = delta_q_;
    } else {
        factor_measure = delta_q_ / (2. * M_PI);
    }

    // collect the reslut from FFTW arrays
    for (int ix = 0; ix < nbin_x_; ix++) {
        double factor_out[2];
        factor_out[0] =
            cos(q_min_ * xbin_[ix]) * factor_measure;
        if (direction_fft_) {
            factor_out[1] =
                -sin(q_min_ * xbin_[ix]) * factor_measure;
        } else {
            factor_out[1] =
                sin(q_min_ * xbin_[ix]) * factor_measure;
        }
        func_x_[ix][0] =
            array_fft_fin_[ix][0] * factor_out[0] -
            array_fft_fin_[ix][1] * factor_out[1];  // real part
        func_x_[ix][1] =
            array_fft_fin_[ix][1] * factor_out[0] +
            array_fft_fin_[ix][0] * factor_out[1];  // imaginary part
    }
    func_x_[nbin_x_][0] = func_x_[0][0];
    func_x_[nbin_x_][1] = func_x_[0][1];

    return true;
}

void FFTransformer::get_array_ini(std::vector<double> &q_out,
                                  std::vector<double> &func_re_out,
                                  std::vector<double> &func_im_out) {
    if (!initialized_) {
        return;
    }

    q_out.clear();
    func_re_out.clear();
    func_im_out.clear();

    for (int iq = 0; iq <= nbin_q_; iq++) {
        q_out.push_back(qbin_[iq]);
        func_re_out.push_back(func_q_[iq][0]);
        func_im_out.push_back(func_q_[iq][1]);
    }
}

void FFTransformer::get_array_fin(std::vector<double> &x_out,
                                  std::vector<double> &func_re_out,
                                  std::vector<double> &func_im_out) {
    if (!initialized_) {
        return;
    }

    x_out.clear();
    func_re_out.clear();
    func_im_out.clear();

    for (int ix = 0; ix <= nbin_x_; ix++) {
        x_out.push_back(xbin_[ix]);
        func_re_out.push_back(func_x_[ix][0]);
        func_im_out.push_back(func_x_[ix][1]);
    }
}

void FFTransformer::write(const char *filename) {
    if (!initialized_) {
        return;
    }

    FILE *fout;
    fout = fopen(filename, "w");
    fprintf(fout,
        "#  q  phi(q).re  phi(q).im  x  psi(x).re  psi(x).im\n");
    for (int iq = 0; iq <= nbin_q_; iq++) {
        int ix = iq;
        fprintf(fout, "%e  %e  %e  %e  %e  %e\n",
            qbin_[iq], func_q_[iq][0], func_q_[iq][1],
            xbin_[ix], func_x_[ix][0], func_x_[ix][1]);
    }
    fclose(fout);
}


이 소스 파일에서는 FFTransformer 클래스의 멤버 함수들을 정의하고 있습니다. 수학적으로는 이전 포스팅에 나온 것과 다르지 않습니다만, FFTransformer::next 함수에서는 푸리에 변환의 대상이 되는 함수의 포인터 구조체 (PtrFuncFFT)를 매개변수로 받아서 func_q_ 배열의 값을 정하게 되죠. 이걸 가지고 FFTW를 실행한 뒤에, 변환된 함수에 대한 정보를 func_x_ 배열에 저장합니다.

한 가지 더 짚고 넘어갈 점이라면, 변환대상이 되는 복소수함수가 정의역에 해당하는 double 형 변수값 뿐 아니라 파라미터를 위한 void 형 포인터 역시 인자로 받고 있다는 점입니다. 여기에는 PtrFuncFFT 구조체의 멤버 포인터 param 을 가져다 넣는 방식을 취하고 있습니다.

이렇게 푸리에 변환을 한 뒤에는 write 함수를 호출해서 파일에 데이터 값들을 기록할 수 있습니다.

test2_fftw.cpp [다운로드]

 

더보기
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include"FFTransformer.h"

typedef struct InfoGauss {
    // mean and width of a Gaussian function
    double mean;
    double sigma;
} InfoGauss;

double func_gaussian(double x, double mean_x, double sigma_x);
double func_fft_re(double q, void *ptr_param);
double func_fft_im(double q, void *ptr_param);

int main(int argc, char *argv[]) {
    // Determine the actual values for mean and width.
    double mean_q = 1.;
    double sigma_q = 0.5;

    // range in the q-space
    double q_min = mean_q - 10. * sigma_q;
    double q_max = mean_q + 10. * sigma_q;
    // lattice spacing in the q-space
    double delta_q = 0.02;

    FFTransformer fft_transform;
    // Initialize the Fourier transformation class
    bool fft_init = fft_transform.init(q_min, q_max, delta_q, false);
    if (!fft_init) {
        fprintf(stderr,
            "ERROR : FFTransformer is not properly initialized.\n");
        exit(1);
    }

    InfoGauss info_gauss;
    info_gauss.mean = mean_q;
    info_gauss.sigma = sigma_q;

    // function pointer
    PtrFuncFFT ptr_func_in;
    ptr_func_in.re = &func_fft_re;  // real part
    ptr_func_in.im = &func_fft_im;  // imaginary part
    ptr_func_in.param = &info_gauss;  // parameter
    // Perform fast Fourier transformation
    bool fft_next = fft_transform.next(ptr_func_in);
    if (!fft_next) {
        fprintf(stderr,
            "ERROR : FFTransformer failed to perform.\n");
        exit(1);
    }

    char filename_output[200];
    if (argc > 1) {
        strcpy(filename_output, argv[1]);
    } else {
        strcpy(filename_output, "func2_gaussian_fft.dat");
    }
    fft_transform.write(filename_output);

    return 0;
}

double func_gaussian(double x, double mean_x, double sigma_x) {
    double dx_scaled = (x - mean_x) / sigma_x;
    double func =
        exp(-0.5 * fabs(dx_scaled * dx_scaled)) /
        (sigma_x * sqrt(2. * M_PI));
    return func;
}

// We are doing Fourier transform of a real Gaussian function.
double func_fft_re(double q, void *ptr_param) {
    InfoGauss *ptr_info = (InfoGauss *)ptr_param;
    return func_gaussian(q, ptr_info->mean, ptr_info->sigma);
}

// So the imaginary part would be zero.
double func_fft_im(double q, void *ptr_param) {
    return 0.;
}


마지막으로 main 함수가 포함된 소스 파일입니다. 여기서 할 일은 변환대상이 되는 복소수함수의 실수와 허수부분을 정의하고 이를 FFTranformer 객체에 넘겨주는 것인데요. 이 함수들은 각각 func_fft_re, func_fft_im 이라는 이름으로 정의되어 있습니다. 이들은 void 형 포인터를 두번째 인자로 받고 있는데, 여기서는 가우스 함수의 평균과 폭을 정의한 InfoGauss 라는 구조체의 포인터를 넘겨주고 있습니다. 물론 이때 InfoGauss 형 포인터에서 void 형 포인터로의 형 변환이 필요하겠죠.

마지막으로 푸리에 변환 객체에 들어갈 PtrFuncFFT 구조체의 멤버 포인터 reim 은 각각 func_fft_refunc_fft_im 함수들의 포인터로 설정됩니다. 파라미터를 위한 포인터 param 역시 이번에는 InfoGauss 구조체를 가리키게 됩니다. 이전 포스팅과 마찬가지로 실수부분은 가우스함수, 허수부분은 0인 함수를 가지고 푸리에 변환을 해보면 동일한 결과를 얻을 수 있습니다. 그리고 이 main 함수는 출력할 파일의 이름을 명령행 인자로 받고 있습니다.

리눅스나 유닉스 환경에서 실행하는 경우 먼저 소스파일들을 컴파일해야 합니다. GNU C++ 컴파일러를 사용할 경우 다음과 같이 할 수 있습니다.
  g++ FFTransformer.cpp -c
  g++ test2_fftw.cpp -c

그리고 오브젝트 파일들을 FFTW 라이브러리와 함께 링크해서 실행파일을 만듭니다.
  g++ test2_fftw.o FFTransformer.o -lfftw3 -lm -o test2_fftw.exec

이렇게 하면 test2_fftw.exec 라는 실행파일이 생성될텐데요. 출력되는 파일의 이름을 명령행 인자로 지정해 줄수 있습니다. 예를들어 func_output.dat 라는 이름으로 저장하고 싶다면 다음과 같이 실행하면 되겠습니다.
  ./test2_fftw.exec func_output.dat

 


 

위 예시에서 푸리에 변환을 수행하기 위한 FFTransformer 클래스를 정의할 때, newdelete 키워드들이 사용되고 있는 것을 보셨을 것입니다. 이들을 이용하면 필요할 때 필요한 만큼만 메모리 공간을 할당받아서 사용할 수 있기 때문에, 효율성이 좋아지게 되죠. 이 동적 메모리 관리에 대한 자세한 사항이 궁금하시다면, 다음 포스팅이 큰 도움이 되리라 생각합니다.

 

 

C++ 동적 메모리 할당 (new, delete 키워드)

여기서는 new 및 delete 키워드를 통해 C++ 프로그램에서 메모리 공간을 동적으로 할당받고 해제하는 방법에 대해서 짚어보겠습니다. 보통 변수나 객체를 소스 코드 내에서 선언하게 되면, 선언한

swstar.tistory.com


추가로 main 함수가 argcargv라는 매개변수를 받고 있고, 이들이 출력파일의 이름을 지정하는데 사용된다는 걸 볼 수 있는데요. 이들을 명령행 인자라고 부르며, 프로그램을 실행할 때 커맨드라인에서 그 값을 지정해 줄 수 있습니다. 더 자세한 사항에 대해서는 다음 포스팅을 참고하면 좋습니다.

 

 

Command-Line Arguments (C/C++ 공통)

C++를 배우기 위해 책을 보는데, command-line arguments에 대한 내용이 있었다. 메인함수를 특별한 방법으로 정의해서, 프로그램을 실행시킬때 커맨드 라인에서 옵션을 지정해줄 수 있다고 한다. int mai

swstar.tistory.com

 


 

같이 알고 있으면 좋은 C/C++ 팁들

 

라이브러리 제작

 

C언어 라이브러리 만들기

자주 쓰는 함수들을 라이브러리 형태로 만들어 두면, 프로그램을 짤 때 편리합니다. 예를 들어서 함수 Function이 mylib.c 라는 소스코드에 정의되어 있고, 프로토타입이 mylib.h 라는 헤더 파일에 선

swstar.tistory.com

 

포트란과의 하이브리드

 

C/C++와 Fortran을 조합한 프로그래밍

수치계산을 위한 프로그램을 짜다 보면, 포트란 함수를 C 혹은 C++ 에서 쓰거나, 그 반대의 경우가 생길 때가 있습니다. 특히 역사가 좀 오래된 모델을 가져다 쓸 때 그렇죠. C언어에서 함수를 특

swstar.tistory.com

 

C언어 동적 메모리 관리

 

C언어 동적 메모리 할당 (malloc, free 함수)

일반적으로 C언어에서 변수나 배열을 선언하면, 해당 코드블록이 끝나서 범위를 벗어날때 까지 메모리를 차지하게 됩니다. 하지만 이렇게 되면 메모리 공간의 낭비가 발생할 수 있죠. 필요할 때

swstar.tistory.com