구조체에서 메모리 동적할당 하는법?

게시판 IDL Q&A 구조체에서 메모리 동적할당 하는법?

이 게시글은 1개 답변과 2명 참여가 있으며 마지막으로  Jonghyuk에 의해 6 년, 3 월 전에 업데이트 됐습니다.

  • 글쓴이
  • #585 답변

    Wonho Lee
    회원

    현재 의료영상 viewer widget 프로그램을 만들고 있습니다
    구조체를 설정하여 위젯간 변수를 주고받고 있습니다

    문제는 불러올 영상의 사이즈가 매번 같은게 아니라서 구조체내에서 영상정보를 가지는 변수를 항상 같은 크기로 메모리 할당을 하지 못하는 점입니다.

    현재 구조체는 다음과 같이 설정하였습니다

    info = {widget_id:widget_id, $
    mImageA:imageinfo, $
    mCTA: 0, $
    mCTF: 0, $
    mFusion1: 50, $
    mTotalFrame: 1, $
    mCurrentFrame: 1, $
    }

    변수가 너무 많아서 info 구조체 안에 각 widget들의 id인 widget_id 구조체와, 영상정보를 가지고 있는 imageinfo 구조체를 설정하였습니다.

    또한 영상을 총 4개까지 불러오는게 목적이라서 imageinfo 구조체 하나를 설정하여 mImageA,mImageB,mImageC, mImageD 이런식으로 동일한 형태의 구조체를 만들려고 합니다.

    imageinfo 구조체는
    imageinfo ={imageinfo, $
    dim: intarr(4), $
    pixdim: fltarr(4), $
    datatype: 0, $
    bitpix: 0, $
    scalefactor: 0.0, $
    dcoff: 0.0, $
    max_value: 0.0, $
    min_value: 0.0, $
    imagedata:ptr_new(/allocate_heap) $
    }

    이와 같이 설정하였습니다.
    실제 영상은 imagedata에 들어올거라서 ptr_new로 크기는 설정하지 않았습니다.

    이제 실제로 파일을 불러오는 버튼을 클릭했을때
    버튼 이벤트에서는 구조체 정보를 가져온 후

    widget_control, event.top, get_uvalue = infoptr
    info = *infoptr
    read_analyze75, file[0], imageinfo=info.mImageA

    파일선택창에서 가져온 파일을 불러오는 프로시져(read_analyze75)로 넘긴 후 영상의 header정보와 실제 영상을 info 구조체안에 있는 imageinfo 구조체로 (info.mImageA)로 넘기는 전달하는 과정을 거칩니다.

    ;불러올 파일 헤더 구조
    ana_hdr = {ana_hdr, $
    sizeof_hdr: 0L, $
    data_type: string(replicate(32B, 10)), $
    db_name: string(replicate(32B, 18)), $
    extents: 0L, $
    session_error: 0, $
    regular: 0B, $
    hkey_un0: 0B, $
    dim: intarr(8), $
    vox_units: string(replicate(32B, 4)), $
    cal_units: string(replicate(32B, 8)), $
    unused1: 0, $
    datatype: 0, $
    bitpix: 0, $
    dim_un0: 0, $
    pixdim: fltarr(8), $
    vox_offset: 0.0, $
    roi_scale: 0.0, $
    funused1: 0.0, $
    funused2: 0.0, $
    cal_max: 0.0, $
    cal_min: 0.0, $
    compressed: 0L, $
    verified: 0L, $
    glmax: 0L, $
    glmin: 0L, $
    descrip: string(replicate(32B, 80)), $
    aux_file: string(replicate(32B, 24)), $
    orient: 0B, $
    origin: intarr(5), $
    generated: string(replicate(32B, 10)), $
    scannum: string(replicate(32B, 10)), $
    patient_id: string(replicate(32B, 10)), $
    exp_date: string(replicate(32B, 10)), $
    exp_time: string(replicate(32B, 10)), $
    hist_un0: string(replicate(32B, 3)), $
    views: 0L, $
    vols_added: 0L, $
    start_field: 0L, $
    field_skip: 0L, $
    omax: 0L, $
    omin: 0L, $
    smax: 0L, $
    smin: 0L $
    }
    openr, lun, filename, /get_lun
    readu, lun, ana_hdr
    free_lun, lun
    close, lun

    ;실제 프로그램에서 필요한 정보를 가지는 구조체 (나중에 widget으로 넘겨줄 구조체)
    imageinfo ={imageinfo, $
    dim: intarr(4), $
    pixdim: fltarr(4), $
    datatype: 0, $
    bitpix: 0, $
    scalefactor: 0.0, $
    dcoff: 0.0, $
    max_value: 0.0, $
    min_value: 0.0, $
    imagedata:ptr_new(/allocate_heap) $
    }

    ;헤더파일 정보에서 필요한 부분만 가져옴
    imageinfo.dim[0] = ana_hdr.dim[1]
    imageinfo.dim[1] = ana_hdr.dim[2]
    imageinfo.dim[2] = ana_hdr.dim[3]
    imageinfo.dim[3] = ana_hdr.dim[4]
    imageinfo.pixdim[0] = ana_hdr.pixdim[1]
    imageinfo.pixdim[1] = ana_hdr.pixdim[2]
    imageinfo.pixdim[2] = ana_hdr.pixdim[3]
    imageinfo.pixdim[3] = ana_hdr.pixdim[4]

    imageinfo.datatype = ana_hdr.datatype
    imageinfo.bitpix = ana_hdr.bitpix
    imageinfo.scalefactor = ana_hdr.roi_scale
    imageinfo.dcoff = ana_hdr.vox_offset

    ;헤더정보를 기반하여 실제 영상크기를 가지는 변수 할당
    img_name = file_dirname(filename, /MARK_DIRECTORY)+file_basename(filename, ‘.hdr’)+’.img’

    case imageinfo.datatype of
    2: *(imageinfo.imagedata)=bytarr(ana_hdr.dim[1], ana_hdr.dim[2], ana_hdr.dim[3], ana_hdr.dim[4])
    4: *(imageinfo.imagedata)=intarr(ana_hdr.dim[1], ana_hdr.dim[2], ana_hdr.dim[3], ana_hdr.dim[4])
    8: *(imageinfo.imagedata)=lonarr(ana_hdr.dim[1], ana_hdr.dim[2], ana_hdr.dim[3], ana_hdr.dim[4])
    16: *(imageinfo.imagedata)=fltarr(ana_hdr.dim[1], ana_hdr.dim[2], ana_hdr.dim[3], ana_hdr.dim[4])
    else: return
    endcase

    image = *(imageinfo.imagedata)

    openr, lun, img_name, /get_lun
    readu, lun, image
    free_lun, lun
    close, lun

    *(imageinfo.imagedata) = image

    위는 영상파일의 헤더정보와 실제 영상을 가져오는 프로시져 입니다.
    여기에서도 imageinfo와 같은 구조를 가지는 구조체를 설정하여서
    헤더정보에서 필요한 부분만 취하고, 실제 영상크기의 변수를 할당하여 영상을 불어오는 과정입니다

    이 프로시져 내에서 테스트를 해봤을때, *(imageinfo.imagedata) 안에 영상이 들어있는 것을 확인할 수 있었습니다.

    그런데 widget 프로그램에서는
    read_analyze75, file[0], imageinfo=info.mImageA
    여기서 받은 info.mImageA에는 파일에서 읽은 정보가 없이 그냥 초기값만 들어있었습니다

    혹시 widget 프로그램 내에서 구조체 포인터 변수(info.mImageA.imagedata) 메모리 항당을 해줘야 하는건가요??

    이러한 구조체 안에 구조체가 있고 또 그 구조체 안에 크기가 가변적인 포인터 변수가 있을때는 프로시져 간 인자를 주고 받을때 어떻게 해야하는지 궁금합니다

    (아…설명이 너무 복잡한가요??ㅜㅜ)
    IDL은 7.1을 쓰고 있습니다

  • #606 답변

    Jonghyuk
    회원

    예, 복잡합니다. ㅎㅎ

    Call by Value와 Call by Reference 의 차이에서 발생하는 문제인 것 같습니다.

    다음과 같은 문장을 적어 주셨는데요, 이 경우 read_analyze75는 info.mImageA에 아무 값도 넣지를 못합니다.
    read_analyze75, file[0], imageinfo=info.mImageA

    구조체의 필드를 인자로 넘겨줄 경우 IDL은 이를 Call by Value로 처리합니다. 즉, info.mImageA의 값을 프로시저로 넘겨줄 수는 있되, 이 프로시저에서 info.mImageA로 값을 넣어줄 수는 없습니다. 다음 예제를 보세요.

    pro change_val, test_key=t
    t=30
    end

    pro test_pass_param
    a={x:0, y:0}
    change_val, test_key=c
    print, c
    change_val, test_key=a.x
    print, a.x
    change_val, test_key=b
    a.x=b
    print, a.x
    end

    실행 결과는
    IDL> test_pass_param
    % Compiled module: CHANGE_VAL.
    % Compiled module: TEST_PASS_PARAM.
    30
    0
    30
    IDL>
    입니다. 즉, 변수를 넘겨 주는 경우 프로시저(함수)는 해당 변수에 어떤 값이든 넣을 수 있습니다. 하지만 구조체의 필드를 넣는 경우는 프로시저(함수)가 값을 넣어줄 수 없어요. 그래서 두 번째 호출에서 a.x는 그대로 0입니다. 이런 경우에 가장 간단한 방법은 세 번째 호출처럼 그냥 변수를 던져서 값을 받아 온 후, 이 값을 구조체 필드에 넣는 것입니다.

    숫자, 수식, 배열의 일부(예를 들면 a[0] 같은), 구조체의 필드(예를 들면 info.data 같은)를 parameter로 넘겨 줄 경우 Call by Value라 하여 값을 받아서 이용은 하되 값을 돌려주는 방법으로는 사용할 수 없습니다.

'구조체에서 메모리 동적할당 하는법?'에 답변달기
글쓴이 정보: