병렬처리 할 때 편하단다

그래서 써보려고 ㅎㅎ


https://golang.org/


https://go-tour-kr.appspot.com


http://knight76.tistory.com/entry/Go-lang-workspace-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

'devel > 개념' 카테고리의 다른 글

Linux Kernel DMA  (0) 2017.03.02
Linux Input Event Driver  (0) 2017.02.23
gpio pull down switch 연결  (0) 2016.11.16
도요타 캠리 급발진 버그 분석 보고서  (0) 2016.11.10
mmap 구현 - 작성중  (0) 2016.08.11
Posted by 쵸코케키








+-----+  +-----------+  +------+  +--------+  +------+

| LED +--+ resistor  +--+ gpio +--+ switch +--+ 3.3V |

+--+--+  +----+------+  +------+  +--------+  +------+

   |          |

+--+--+    +--+--+

| GND |    | GND |

+-----+    +-----+





'devel > 개념' 카테고리의 다른 글

Linux Input Event Driver  (0) 2017.02.23
golang 고랭지 농업이 아니라 go 언어  (0) 2016.12.01
도요타 캠리 급발진 버그 분석 보고서  (0) 2016.11.10
mmap 구현 - 작성중  (0) 2016.08.11
stm32f4 절전모드  (0) 2016.08.10
Posted by 쵸코케키




BarrSlides_FINAL_SCRUBBED.pdf

모든 저작권은 BARR group에게 있음

'devel > 개념' 카테고리의 다른 글

golang 고랭지 농업이 아니라 go 언어  (0) 2016.12.01
gpio pull down switch 연결  (0) 2016.11.16
mmap 구현 - 작성중  (0) 2016.08.11
stm32f4 절전모드  (0) 2016.08.10
__GFP_COMP - compound page  (0) 2016.07.26
Posted by 쵸코케키

mmap 구현 방식 2가지

ldd 많이 참조함, 옅은 지식으로 쓴 내용이라 틀릴 수 있음

mmap의 역할?

kernel 공간 혹은 하드웨어 장치에 있는 메모리를 복사하는 과정 없이 user 공간에게 제공
rw가 엄청나게 발생하는 경우에 꽤나 의미있는 성능향상을 보여줄 수 있다
c 어플리케이션에서 mmap 함수를 호출하면 device driver의 mmap 함수가 호출된다
그 함수를 구현하는게 목표


어플리케이션 영역

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,
          int fd, off_t offset);
int munmap(void *addr, size_t length);

자세한 설명은 man 페이지 참조
flag는 계속 늘어나는데 MAP_HUGETLB 같이 huge page를 쓸 때 필요한 옵션도 있다
그냥 일반적인 flag로는 MAP_SHARED(다른 프로세스랑 같이 공유) 가 있겠다
prot는 page의 권한에 관한 내용이다
페이지가 읽힐 예정인지 쓰거나 실행될련지 등등


mmap 구현

요약 : 아래의 함수들을 잘 조합해서 사용하면 된다

io_remap_pfn_range()
remap_pfn_range()

아니면 fault 를 처리하는 방식으로 구현해도 ok

vm_insert_page()
vm_insert_pfn()

fault 처리에 주로 사용된다

원형

include/linux/fs.h
struct file_operation {
    ...
    int (*mmap) (struct file *, struct vm_area_struct *);
}

remap_pfn_range 사용

remap_pfn_range - remap kernel memory to userspace
system RAM을 맵핑하고 싶을 때 사용
참고 : io_remap_pfn_range은 장치의 I/O memory 즉 phys_addr_t로 표현되는 놈을 매핑하고 싶을 때 사용
nommu가 아닌이상 동일

내가 파악한 바로는(틀릴 수 있지만 ㅠㅜ)

  1. 유저에서 mmap을 호출하면 (사용할 수 있는 커널 메모리 쫌만 주세요. 대신 제가 알아볼 수 있는 주소로요)
  2. 위의 요청 정보가 vma 형태로 driver로 들어오고(메모리 정보)
  3. 인제 개발자는 가지고 있던(미리 할당해두었던) 메로리를 vma랑 붙여주는데
  4. 그 때 사용하는 도구가 remap_pfn_range 인가보다

이 함수는 userspace의 addr ~ addr+size 범위의 virtual address를 위한 page table을 만든다
이 함수는 pfn<<PAGE_SHIFT ~ (pfn<<PAGE_SHIFT) + size 까지 해당하는 물리 메모리 영역에 영향을 준다

include/linux/pfn.h
#define PFN_PHYS(x)     ((phys_addr_t)(x) << PAGE_SHIFT)
#define PHYS_PFN(x)     ((unsigned long)((x) >> PAGE_SHIFT))

int remap_pfn_range(struct vm_area_struct *vma,  
                    unsigned long addr, 
                    unsigned long pfn,
                    unsigned long size, 
                    pgprot_t prot)

vma : 매핑될 virtual memory area - 변태가 아닌 이상 mmap 호출될 때 vma 인자가 같이 딸려오므로 그대로 쓰면 된다. 하지만 변태라면?!
addr : target user address to start at
pfn : page frame number of kernel memory
보통 physical address >> PAGE_SHIFT 한 값이다
이 physical address에 addr(target user address, virtual address)가 매핑되게 된다

size : 바이트 단위의 매핑될 영역 크기. 보통 vma->vm_end - vma->vm_start
prot : page protection flag, 보통 vma->vm_page_prot 값을 사용한다

이 함수를 호출할 때 흔히 다음과 같이 한다(아래 참조)

예시 : drivers/uio/uio.c

static const struct file_operations uio_fops = {
    ...
    .mmap = uio_mmap,
}

static int uio_map(struct file *filep, struct vm_area_struct *vma)
{
    ...
    return uio_mmap_physical(vma);
}

static int uio_mmap_physical(struct vm_area_struct *vma)
{
    ...
    return remap_pfn_range(vma,
                           vma->vm_start,
                           mem->addr >> PAGE_SHIFT,    //미리 할당해두었던 메모리 
                           vma->vm_end - vma->vm_start,
                           vma->vm_page_prot);
}

조금 형태가 다르긴 한데 이런 것도 있다
drivers/vfio/pci/vfio_pci.c

static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
{
    ...


    pgoff = vma->vm_pgoff &
            ((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);    //???

    u64 phys_len = pci_resource_len(pdev, index);    
    req_start = pgoff << PAGE_SHIFT;
    req_len = vma->vm_end - vma->vm_start;

    if(phys_len < PAGE_SIZE || req_start + req_len > phys_len)    //크기 검사
        return -EINVAL;

    vma->vm_pgoff = (pci_resource_start(pdev, index) >> PAGE_SHIFT) + pgoff;

    return remap_pfn_range(vma, vma->start, vma->vm_pgoff,
                            req_len, vma->vm_page_prot);
    //어차피 remap_pfn_range를 호출하면 vma->vm_pgoff = pfn 이 된다
}

아니면 이런 애들도 있다
sound/core/pcm_native.c

int snd_pcm_lib_default_mmap(...)
{
    area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
#ifdef CONFIG_GENERIC_ALLOCATOR
    if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) {
            area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
            return remap_pfn_range(area, area->vm_start,
                            substream->dma_buffer.addr >> PAGE_SHIFT,
                            area->vm_end - area->vm_start, area->vm_page_prot);
    }    
#endif /* CONFIG_GENERIC_ALLOCATOR */
#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
    if (!substream->ops->page &&
        substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
            return dma_mmap_coherent(substream->dma_buffer.dev.dev,
                                     area,
                                     substream->runtime->dma_area,
                                     substream->runtime->dma_addr,
                                     area->vm_end - area->vm_start);
#endif /* CONFIG_X86 */
    /* mmap with fault handler */
    area->vm_ops = &snd_pcm_vm_ops_data_fault;
    return 0;
}

기타 다른 예시
drivers/infiniband/hw/nes/nes_verbs.c

static int nes_mmap(struct ...)
{
    ...
    remap_pfn_range( ...
    virt_to_phys >> PAGE_SHIFT ...)
    ...
}

.pgprot

잘 몰라서 생략
대략 cache 쓸껀지 말껀지 관한 내용인데
pgprot_noncached, pgprot_writecombine, pgprot_writethrough
등이 있다


기타

drivers/media/platform/omap/omap_vout.c
OMAP 24xx camera controller 코드

처음 매몰이 할당 코드

virt_addr = omap_vout_alloc_buffer(vout->buffer_size, &phy_addr);
vout->buf_virt_addr[i] = virt_addr;
vout->buf_phy_addr[i] = phy_addr;

unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
{
    u32 order, size;
    unsigned long virt_addr, addr;

    size = PAGE_ALIGN(buf_size);    //참고로 가로px * 세로px * bpp(bits per pixel)
    order = get_order(size);
    virt_addr = __get_free_pages(GFP_KERNEL, order);
    addr = virt_addr;

    *phys_addr = (u32) virt_to_phys((void *) virt_addr);
    return virt_addr;
}

mmap 코드

vm_operations_struct omap_vout_vm_ops
    .open = vout->mmap_count++; 역할 수행(mmap )
    .close =  vout->mmap_count--; 역할 수행

mmap 호출한다고 해서 mmap open까지 같이 호출되지는 않는다
놀랍게도 r/w 둘 다 open을 호출하지 않는다
open은 process가 fork할 때 불려진다
그리고 vma에 대한 새로운 reference를 생성한다

static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
{
    unsigned long start = vma->vm_start;
    unsigned long size = vma->vm_end - vm->vm_start;
    ...
    void* pos = (void *)vout->buf_virt_addr[i];            //kernel logical address(virtual address)
    vma->vm_pgoff = virt_to_phys((void *) pos) >> PAGE_SHIFT;    //physical
    vma->vm_ops = &omap_vout_vm_ops;
    ...

    while(size > 0) {
        unsigned long pfn;
        pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;        //물리 주소 획득
        if(remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
            return -EAGAIN;
        start += PAGE_SIZE;
        pos += PAGE_SIZE;
        size -= PAGE_SIZE;
    }

    vout->mmap_count++;        
}

remap_pfn_range에 size를 한 번에 넣는게 아니라 PAGE_SIZE로 나눠 하는 이유?
pixel size가 크다고 해도 어차피 kmalloc 한계인 MAX_ORDER(2^ 10 ~11, 1024) * PAGE_SIZE(4096B) = 4MB or 8MB 이내 범위로 메모리가 할당되어 있다
왜 이짓을 하냐면 메모리가 cma같은게 아닌이상 크게 할당이 안되고 PAGE_SIZE 크기로 할당해서 일듯?
vma 유저 메몰희랑 pfn 물리 매몰의랑

추가 참고 : http://www.cs.fsu.edu/~baker/devices/notes/ch15.html#(34)

그 외 fault 직접 관리

vm_opeartions_struct 의 fault 함수를 직접 구현해야 함
결론적으로 vmf->page = page 를 해주어 메모리를 제공하면 끝
제공해줄 page는 어디서 얻냐고?
여러가지 구현 방법이 있는데 get_zeroed_page 같은 함수로 미리 얻어놓거나
필요할 때마다 획득하거나 등등

예시 : sound/usb/usx2y/usX2Yhwdep.c, sound/core/memalloc.c
mmap이 호출되면 __get_free_pages 로 shared memory 호출하고
fault가 호출되면 아래의 함수가 호출된다

static int snd_us428ctls_vm_fault(struct vm_area_struct *area, 
                                  struct vm_fault *vmf)
{
    ...
    offset = vmf->pgoff << PAGE_SHIFT;        //physical to kernel logical
    vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->us428ctls_sharedmem + offset;    
    //미리 얻어놨던 메모리 조금씩 제공
    page = virt_to_page(vaddr);
    vmf->page = page;
    get_page(page);                // 나 이 페이지 쓴다!
}

혹은 다른 예시 - dma 같은게 필요 없는 경우
drivers/uio/uio.c

static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
    page = vmalloc_to_page(addr);
    get_page(page);
    vmf->page = page;
}

drivers/staging/android/ion/ion.c

static int ion_vm_fault(staruct vm_area_struct *vma, struct vm_fault *vmf)
{
    ...
    vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
    ...
}

그 외 dma common mmap

include/linux/dma-mapping.h

struct dma_map_ops {
    ...
    int (*mmap)(struct device *, struct vm_area_struct *,
                    void *, dma_addr_t, size_t, struct dma_attrs *attrs);
}

drivers/base/dma-mapping.c 참고
int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
                    void *cpu_addr, dma_addr_t dma_addr, size_t size)
{
        int ret = -ENXIO;
#if defined(CONFIG_MMU) && !defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP)
        unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr));
        unsigned long off = vma->vm_pgoff;

        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
                            include/linux/mm.h 

        if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret))
                return ret;

        if (off < count && user_count <= (count - off)) {
                ret = remap_pfn_range(vma, vma->vm_start,
                                      pfn + off,
                                      user_count << PAGE_SHIFT,
                                      vma->vm_page_prot);
        }   
#endif  /* CONFIG_MMU && !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */

        return ret;
}

http://anster.egloos.com/m/2141358ㅁ

'devel > 개념' 카테고리의 다른 글

gpio pull down switch 연결  (0) 2016.11.16
도요타 캠리 급발진 버그 분석 보고서  (0) 2016.11.10
stm32f4 절전모드  (0) 2016.08.10
__GFP_COMP - compound page  (0) 2016.07.26
ld linker script 예시  (0) 2016.07.25
Posted by 쵸코케키

2016. 8. 10. 13:43 devel/개념

stm32f4 절전모드

STM32F4xx 시리즈의 sleep, stop mode에 대해



STM32F4xx block diagram


 stm32f41x_block_diagram

시리즈 마다 다르겠지만 대충 이런 식으로 생겼다

일단은 넘어가자




#Sleep Mode

Sleep Mode는 아래 함수로 쉽게 진입이 가능한데

HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);

Wakeup 조건이 모든 인터럽트기 때문에 sleep으로 들어가기 전에 SysTick 관련 interrupt도 꺼야 한다

안 그러면 잠자리에 눕자마자 일어나는 불상사가......

SysTick 때문에 바로 깨어날 경우 아래와 같이 Tick을 잠시 중단 시키면 된다

 

HAL_SuspendTick();

HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);

HAL_ResumeTick();

 

1번 인자로 PWR_MAINREGULATOR_ON를 이용해도 좋다 그런데 MR이 뭔지 모르겠다

2번째 인자로 PWR_SLEEPENTRY_WFE를 사용해도 된다

여기서 Event가 뭐인고 하니 EXTIexception 등등

자세한 내용은 D022708, 48p Wakeup from WFE 를 참고 바란다

 

 

# 1.2v domain - DM00127514, 112p

core, memory, digital peripherals

 

# STOP MODE - DM00127514, 113p, 120p

1.2v domain, PLLs, HSI, HSE RC oscillator disabled

Internal SRAM, register contents are preserved

SRAM 내용 유지(SRAM에 관한 상세 내용은 아래에), 레지스터 내용 유지

그리고 각종 oscillator domain 관련은 block diagram을 확인 하여 영향도를 체크하자

 

# HSI, HSE - DM00127514, 135p

상세 내역은 pdf 참조

일단은 AHB에 연결된 아해들이 정상 동작 않겠구나 생각해두자

 

그건 그렇고 stop mode에도 2가지 모드가 있다

이하 STOP MODE 해석 안 하는 게 더 나을 꺼 같아서 생략

 

Normal mode

the 1.2 V domain is preserved in nominal leakage mode.

It is the default mode when the main regulator (MR) or the low-power regulator (LPR) is enabled.

- HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);

 

Under drive mode

the 1.2 V domain is preserved in reduced leakage mode.

This mode is only available when the main regulator or the lowpower regulator is in low voltage mode

- HAL_PWREx_EnterUnderDriveSTOPMode(PWR_LOWPOWERREGULATOR_UNDERDRIVE_ON, PWR_SLEEPENTRY_WFI);

 

Under drive mode가 전기 더 덜 먹는다는 이야기

대신 wakeup time이 더 소모 된다.

          

 

#SRAM?

2.3.1 Embedded SRAM, 68p, 71p 참조

MCU 내부에 있는 램. 용량 매우 작다

linker script 작성에 따라서 다르긴 하지만 external RAM 없다는 가정하에

일반적으로 흔히 우리가 생각하는 heap stack이 살아 숨쉬는 RAM이라고 보면 된다

 

STOP mode에서 Under drive Mode 로 진입하면 더욱 저전력 가능

대신 wakeup time이 더 소모

wakeup time의 딜레이를 사용자가 줘야 하는 게 아니라 그냥 좀 더 걸린다 정도로 이해하면 될 듯

그래도 머 ns 단위로 전부 깨어나지 않을까

각각 딜레이 보면 < Xns 이런 식으로 되어있고 정확한 값은 없음

아래 Table 20. Stop operating modes 참고



'devel > 개념' 카테고리의 다른 글

도요타 캠리 급발진 버그 분석 보고서  (0) 2016.11.10
mmap 구현 - 작성중  (0) 2016.08.11
__GFP_COMP - compound page  (0) 2016.07.26
ld linker script 예시  (0) 2016.07.25
컴퓨터 프로그래밍 전반적인 지식 기초 소양  (0) 2016.07.14
Posted by 쵸코케키


https://lwn.net/Articles/619514/


A compound page is simply a grouping of two or more physically contiguous pages into a unit that can, in many ways, be treated as a single, larger page. They are most commonly used to create huge pages, used within hugetlbfs or thetransparent huge pages subsystem



'devel > 개념' 카테고리의 다른 글

mmap 구현 - 작성중  (0) 2016.08.11
stm32f4 절전모드  (0) 2016.08.10
ld linker script 예시  (0) 2016.07.25
컴퓨터 프로그래밍 전반적인 지식 기초 소양  (0) 2016.07.14
64bit linux kernel memory layout  (1) 2016.05.31
Posted by 쵸코케키

출처

http://www.hertaville.com/a-sample-linker-script.html




/******************************************************************************
    * This linker file was developed by Hussam Al-Hertani. Please use freely as
    * long as you leave this header in place. The author is not responsible for any
    * damage or liability that this file might cause.
******************************************************************************/

   /* Entry Point */
   ENTRY(Reset_Handler)

   /* Specify the memory areas */
   MEMORY
   {
     FLASH (rx)      : ORIGIN = 0x08000000, LENGTH = 0x10000 /*64K*/
     RAM (xrw)       : ORIGIN = 0x20000000, LENGTH = 0x02000 /*8K*/
   }

   /* define stack size and heap size here */
   stack_size = 1024;
   heap_size = 256;

   /* define beginning and ending of stack */
   _stack_start = ORIGIN(RAM)+LENGTH(RAM);
   _stack_end = _stack_start - stack_size;

   /* Define output sections */
   SECTIONS
   {
     /* The startup code goes first into FLASH */
     .isr_vector :
     {
       . = ALIGN(4);
       KEEP(*(.isr_vector)) /* Startup code */
       . = ALIGN(4);
     } >FLASH

     /* The program code and other data goes into FLASH */
     .text :
     {
       . = ALIGN(4);
       *(.text)           /* .text sections (code) */
       *(.text*)          /* .text* sections (code) */
       *(.rodata)         /* .rodata sections (constants, strings, etc.) */
       *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
       *(.glue_7)         /* glue arm to thumb code */
       *(.glue_7t)        /* glue thumb to arm code */
       . = ALIGN(4);
       _etext = .;        /* define a global symbols at end of code */
     } >FLASH

      .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
       .ARM : {
       __exidx_start = .;
         *(.ARM.exidx*)
         __exidx_end = .;
       } >FLASH

     /* used by the startup to initialize data */
     _sidata = .;

     /* Initialized data sections goes into RAM, load LMA copy after code */
     .data : AT ( _sidata )
     {
       . = ALIGN(4);
       _sdata = .;        /* create a global symbol at data start */
       *(.data)           /* .data sections */
       *(.data*)          /* .data* sections */

       . = ALIGN(4);
       _edata = .;        /* define a global symbol at data end */
     } >RAM

     /* Uninitialized data section */
     . = ALIGN(4);
     .bss :
     {
       /*  Used by the startup in order to initialize the .bss secion */
       _sbss = .;         /* define a global symbol at bss start */
       __bss_start__ = _sbss;
       *(.bss)
       *(.bss*)
       *(COMMON)

       . = ALIGN(4);
       _ebss = .;         /* define a global symbol at bss end */
       __bss_end__ = _ebss;
     } >RAM

       . = ALIGN(4);
       .heap :
       {
           _heap_start = .;
           . = . + heap_size;
                   _heap_end = .;
       } > RAM

       /* Remove information from the standard libraries */
       /DISCARD/ :
       {
           libc.a ( * )
           libm.a ( * )
           libgcc.a ( * )
       }

       .ARM.attributes 0 : { *(.ARM.attributes) }
   }


'devel > 개념' 카테고리의 다른 글

stm32f4 절전모드  (0) 2016.08.10
__GFP_COMP - compound page  (0) 2016.07.26
컴퓨터 프로그래밍 전반적인 지식 기초 소양  (0) 2016.07.14
64bit linux kernel memory layout  (1) 2016.05.31
헤더파일 전역변수 중복 오류  (0) 2016.04.21
Posted by 쵸코케키

http://www.edwardbosworth.com/My5155Textbook/MyText5155_AFrontMatter.htm


강추

'devel > 개념' 카테고리의 다른 글

__GFP_COMP - compound page  (0) 2016.07.26
ld linker script 예시  (0) 2016.07.25
64bit linux kernel memory layout  (1) 2016.05.31
헤더파일 전역변수 중복 오류  (0) 2016.04.21
EAS(Energy-Aware Scheduler) 스케쥴러 정리  (0) 2016.03.24
Posted by 쵸코케키

64비트 리눅스 커널메모리 맵

Documentation/x86/x86_64/mm.txt


AMD64 canonical address form 이라고도 하는듯


상위 - 커널이 사용(40bit?)

하위 - 유저스페이스(47bit)

나머지 - hypervisor용 등등 그냥 비워둠


하지만 kmalloc 제한은 엄청 작다

신형 대용량 메모리 할당 기법들을 사용해야 한다



기타 64bit low memory 관련 글

http://www.criticalworld.co.kr/?p=56

Posted by 쵸코케키

헤더파일 전역변수 중복 오류

File:Program memory layout.pdf


재미난 일이 있었다

gcc에서는 문제 없는 코드가

visual studio 에서는 컴파일이 안되는 현상이 있었다


결론 요약

1. gcc랑 visual studio랑 헤더 파일 취급이 다름

2. 변수, 함수의 선언은 중복가능, 정의와 동시에 선언은 불가

3. header 파일은 extern 변수 선언, c 파일에는 변수 선언 및 정의



#1. gcc랑 visual studio랑 헤더 파일 취급이 다름 

type.h, main.c, func.c

*** type.h

#ifndef _type_h_

#define _type_h_

#include <stdio.h>


void show_var(void);

#endif



*** main.c

#include "type.h"

int var = 7;


int main()

{

show_var();

return 0;

}



*** func.c

#include "type.h"

extern int var;


void show_var(void)

{

printf("%d\n", var);

}




별거 아니다 그런데 위의 내용이 gcc에서는 오류 없이 컴파일 되었으나

visual studio에서는 func.c가 int var를 못 찾겠다고 오류를 뱉고 컴파일에 실패했다

중략하고 결론만 이야기 하면 type.h에 extern int var를 써줘야 하는게 원래 맞다고 한다


그런데 참 신기한 일이 main.c의 int var = 7를 type.h로 이동 시켰을 때다

visual studio는 그냥 컴파일이 된다 그러나

gcc는 ld(linker) 단계에서 (.rodata + @) multiple definition 오류가 난다

이건 사실 gcc쪽이 맞는거 같다


왜냐고 생각해보니 헤더를 파일에 복사할 때 일단 main.c, func.c에 _type_h_가 정의 된적 없으니

void show_var(void);랑 int var = 7;를 붙일 것이다

그리고 마지막에 모든 파일을 하나로 합치는 단계에서 main.c에도 int var = 7;이 있고

func.c에도 int var = 7;이 있으니 중복이 되어 오류를 출력하는 것이리라


그런데 왜 .rodata + @ 오류일까? 

initialized data니까 .data + @가 맞지 않으려나 


기타



#2. 변수, 함수의 선언은 중복가능, 정의와 동시에 선언은 불가

테스트 해봤다

*** test.c

void a(int);

void a(int);


int c;

int c;


int main()

{

c = 4;

a(c);

return 0;

}


void a(int b)

{

b+=8;

}


gcc에서 오류 없이 컴파일 된다 -Wall 해도 고요하다

but 

int c = 6;

int c = 3; 

이러면 당연하게 안된다

이 이상해보이는 바보 코드가 위의 의문스러운 문제의 해답이 되리라 :)



Posted by 쵸코케키
이전버튼 1 2 3 이전버튼

블로그 이미지
chocokeki
쵸코케키

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

최근에 올라온 글

최근에 달린 댓글

글 보관함