// struct sample
// struct7.c
// 구조체를 사용하여 링크드 리스트 만들기

#include <stdio.h>

// 1) 구조체 정의 (typedef)
typedef struct score
{
    char name[20];
    int  kor;
    struct score *next;
} SS;

int main(int argc, char *argv[])
{
    // 2) 구조체 선언
    SS s1={"park",100};
    SS s2={"kim",90};
    SS s3={"lee",80};

    SS *p;

    s1.next = &s2;
    s2.next = &s3;
    s3.next = '\0';


    for(p=&s1 ; p ; p = p->next)
    {
        printf("%s --- %d\n",p->name, p->kor);
    }

    return 0;
}

펌 : http://cafe.naver.com/itdocument.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=382

전문대 시절 링크드리스크가 이해가 되질 않아서 얼마나 골머리를 굴렸는지... 떱

#include <stdio.h>

void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}

void main(int argc, char *argv[])
{
int *a, *b;

a = 30;
b = 20;

swap(&a, &b);

printf("%d, %d \n", a, b);
}

정말 간단하지않은가? 만약 포인터로 참조를 하지 않으면 전역 변수를 선언해서 전역변수에 값에 스왑된 값을 처리하여 출력해야 하지만... 포인터를 사용하면 이리 간단하다. 포인터를 공부해 두면 그리 나쁘지는 않을 것이다. 

'구조적언어 > C' 카테고리의 다른 글

링크드 리스크 만들기  (0) 2010.06.07
#3. 공유메모리 사용설명서  (0) 2009.12.17
#2. 공유메모리 클라이언트 소스  (0) 2009.12.17
#1. 공유메모리 서버 소스  (0) 2009.12.17
hello World를 찍어보자.  (0) 2009.12.17


정리를 잘 해놓아서 올림

'구조적언어 > Asm' 카테고리의 다른 글

nasm-2.07-win32.zip  (0) 2009.12.20
nasm 2.01 옵션  (0) 2009.12.20

프리웨어라서 올리긴 하는데 제제가 있으면 삭제하겠노라...

'구조적언어 > Asm' 카테고리의 다른 글

어셈블리 강의 자료  (0) 2009.12.20
nasm 2.01 옵션  (0) 2009.12.20

NASM에서 파일을 어셈블하기 위해 다음과 같이 입력할 수 있다.

c:\>nasm -f <format> <filename> [-o <output>]
 

 

NASM의 추가적인 사용법을 알고싶으면,

nasm -h

가능한 출력 파일의 형식 리스트를 보고싶으면,

nasm -hf

를 입력하면 된다.


-o 옵션 : 출력파일 이름 설정

c:\>nasm -f bin program.asm -o program.com

c:\>nasm -f bin driver.asm -odriver.sys
 


NASM은 보통 자동으로 정해진 출력형식에 따라 출력파일이름을 정해준다. MicroSoft Object 파일 형식(obj와 win32)같은 경우에는, 소스파일에서 .asm 확장자(다른 확장자도 상관없음)를 삭제하고, .obj로 변경시켜준다. Unix Object 파일형식(aout, coff, elf, as86)은 .o로 변경한다. rdf는 .rdf를, bin은 간단히 확장자를 없앤다.(myfile.asm은 myfile이 된다)

출력파일이 이미 존재한다면 덮어쓰기를 한다. 입력파일과 이름이 같으면 경고를 출력하고, nasm.out이라는 이름으로 출력파일을 생성한다.

자동방식을 이용하기 싫을 경우에는 -o 옵션을 이용하여 출력파일이름을 직접 정의해줄 수 있다. -o옵션 뒤에 파일이름을 입력하면 된다.(스페이스 유무에 상관없음)


-f 옵션 : 출력파일형식 설정

-f 옵션을 입력하지 않아도 NASM이 자동으로 선택해준다.(버전마다 다르겠지만, 보통 bin으로 한다 : NASM을 직접 컴파일할 경우에는 OF_DEFAULT 옵션을 이용하여 변경할 수 있다)

-o 옵션과 같이 스페이스에 상관없이 -f 뒤에 출력파일형식을 정하면 된다.(-f elf나 -felf는 같다)

가능한 출력파일형식을 보고싶으면 -hf 옵션을 이용해보자.

c:\>nasm -hf

...

valid output formats for -f are (`*' denotes default):

* bin flat-form binary files (e.g. DOS .COM, .SYS)

aout Linux a.out object files

aoutb NetBSD/FreeBSD a.out object files

coff COFF (i386) object files (e.g. DJGPP for DOS)

elf32 ELF32 (i386) object files (e.g. Linux)

elf ELF (short name for ELF32)

elf64 ELF64 (x86_64) object files (e.g. Linux)

as86 Linux as86 (bin86 version 0.3) object files

obj MS-DOS 16-bit/32-bit OMF object files

win32 Microsoft Win32 (i386) object files

win64 Microsoft Win64 (x86-64) object files

rdf Relocatable Dynamic Object File Format v2.0

ieee IEEE-695 (LADsoft variant) object file format

macho NeXTstep/OpenStep/Rhapsody/Darwin/MacOS X object files

c:\>
 

 

-l 옵션 : 리스트 파일 생성

c:\>nasm -f elf myfile.asm -l myfile.lst
 
-l <filename> 옵션을 사용할 경우 왼쪽에는 주소와 생성된 hex코드 및 오른쪽에는 매크로가 적용된 실제 소스가 있는 소스-리스트 파일을 생성한다.(매크로에서 전개를 원하지 않는다는 요청을 한 경우를 제외)

6 00000003 B013 mov al, 0x13

7 00000005 B400 mov ah, 0x00

8 00000007 CD10 int 10h

9

10 fin:

11 00000009 F4 hlt

12 0000000A EBFD jmp fin
 

 

-F 옵션 : 디버깅정보 형식 선택

이 옵션은 출력파일에 맞는 디버거에서 사용될 디버깅정보 형식을 선택하는데 사용된다.


-g 옵션 : 디버깅 정보 설정

이 옵션은 선택된 형식으로 디버깅 정보를 생성한다. -F 옵션이 없는 경우에는 출력파일형식에 따라 생성한다. 선택된 출력파일형식에 생성할 수 있는 디버깅정보가 없는 경우 -g 옵션은 무시된다.


-y 옵션 : 가능한 디버깅정보 형식 출력

c:\>nasm -f elf -y myfile.asm
 


현재 설정된 출력파일형식에 따른 가능한 디버깅정보 형식을 화면에 표시해준다. 기본설정은 *로 표시해준다.


-M 옵션 : Makefile의 종속성 생성

c:\>nasm -M myfile.asm > myfile.dep
 


이 옵션은 Makefile 종속성을 생성하여 stdout에 출력한다.


-E 옵션 : 에러를 파일로 저장

c:\>nasm -E myfile.err -f obj myfile.asm
 


MS-DOS 환경에서는 프로그램의 standard-error를 파일로 변경하는 방법이 있지만 어렵다. NASM은 보통 경고와 에러 메시지를 stderr로 출력하기 때문에 에디터에 불러오는 것이 어렵다. 그래서 standard error가 아닌 특정 파일로 출력해주는 -E 옵션을 제공한다.


-s 옵션 : 에러를 stdout으로 출력

c:\>nasm -s -f obj myfile.asm | more
 


-s 옵션은 에러 메시지를 stderr이 아닌 MS-DOS에서 재조작이 가능한 stdout으로 출력한다.

myfile.asm을 어셈블한 결과를 more 프로그램에 연결하려면 다음과 같이 입력한다.


-X 옵션 : 에러 출력 형식을 선택

이 옵션은 NASM에서 출력하는 에러 메시지의 형식을 선택하는데 사용된다.

현재, 2가지 옵션을 선택할 수 있다.

-Xgnu (GNU 형식)

filename.asm:65: error: specific error message

-Xvc (Microsoft Visual C++ 형식)

filename.asm(65) : error: specific error message


-i 옵션 : Include 파일탐색 디렉터리 설정

c:\>nasm -ic:\macrolib\ -f obj myfile.asm
 


NASM은 소스파일의 %include 구문을 현재 디렉터리뿐만 아니라 사용자가 -i 옵션으로 정해준 디렉터리까지 검색을 한다. 그래서 매크로 파일 라이브러리를 포함할 수 있다. (-i 옵션 사이에 스페이스는 상관없음)

소스코드 이식성에 중점을 둬서, OS가 동작하는 파일이름변경에 대해서는 알지 못한다. 그렇기 때문에 -i 옵션에서 입력한 디렉터리를 파일이름에 연결하여 이용한다. Window같은 경우에는 역슬래시(\)를 이용해야하고, Uix에서는 슬래시(/)를 이용해야한다. (이 특징의 장점을 이용할 수 있다. -ifoo 라고 옵션을 입력하면, %include "bar.i"에서 foobar.i 파일을 탐색하게 된다.)

Unix 시스템에서 /usr/include 와 같은 표준 include를 탐색하길 원한다면, NASM 환경변수에 -i 옵션을 하나 이상 입력하면 된다.(Section 2.1.13 참고)

많은 C 컴파일러에 호환되는 Makefile을 위해 -I로 사용될 수도 있다.


-p 옵션 : 미리 파일을 포함

c:\>nasm myfile.asm -p myinc.inc
 


-p 옵션을 이용하여 소스파일에 파일을 포함할 수 있다.

는 myfile.asm의 파일 시작부분에 %include "myinc.inc"를 추가하여 동작을 한다.

-I, -D, -U 옵션의 호환을 위해 -P 옵션으로도 사용된다.


-d 옵션 : 미리 정의된 Macro

c:\>nasm myfile.asm -dFOO=100
 


-p 옵션은 %include로 대체되는 반면, -d 옵션은 %define으로 대체된다.

매크로를 빼먹은 경우 이용하면 된다. (예로, -dFOO는 소스코드에 %define FOO를 해준 것과 같다) 이 옵션은 어셈블리하는 순간에 옵션을 이용하여 %ifdef에 사용되는 매크로를 지정해주는 방식으로 주로 이용된다.(주로 -dDEBUG)

많은 C 컴파일러에 호환되는 Makefile을 위해 -D로 사용될 수도 있다.


-u 옵션 : 매크로 해지

c:\>nasm myfile.asm -dFOO=100 -uFOO
 


-u 옵션은 명령줄에서 앞에 입력된 -p나 -d에 사용된 매크로를 해지할 수 있다. 이 옵션은 Makefile에서 지정된 옵션을 덮어쓰는데 유용하게 사용된다.

많은 C 컴파일러에 호환되는 Makefile을 위해 -U로 사용될 수도 있다.


-e 옵션 : Preprocess 모드

NASM에서 preprocess 모드를 지원해준다. -e 옵션을 사용하면 입력파일에서 매크로참조를 모두 확장시키고, 주석이나 선처리 구문을 모두 삭제한다. 그리고 결과를 standard output에 출력한다. (파일로 저장하고 싶으면 -o 옵션을 이용하면 된다.)

이 옵션에서는 기호의 값에 따라서 표현식을 계산해야하는 선처리 구문 같은 경우에는 동작하지 않는다.

%assign tablesize ($-tablestart)

이 코드는 preprocess-only 모드에서는 에러를 발생한다.


-a 옵션 : Preprocess 금지 모드

NASM이 컴파일러 맨 마지막에 사용되면, 컴파일 시간의 향상을 위하여 컴파일러가 preprocess를 모두 했다고 가정하고 이것을 하지 않는 것이 바람직하다. -a 옵션을 이용하면 NASM은 preprocess를 하지 않는다.


-t 옵션 : TASM 호환성 모드 동작

NASM은 볼랜드의 TASM과 제한적으로 호환한다.


-w 옵션 : 어셈블리 경고 동작/해지

c:\>nasm -f bin myfile.asm -w+orphan-labels
 


NASM은 출력파일을 생성하는데 지장은 없지만, 문제 소지가 있는 경우를 관찰한다. 이러한 경우, Error처럼 보고가 되지만, ‘warning'이라는 메시지로 대체된다. warning을 출력파일 생성에 지장이 없으며, OS에는 어셈블리 성공으로 처리된다.

이런 경고는 유용할 수도 있고, 아닐 수도 있다. 그렇기 때문에 -w 옵션을 제공한다. 예로들어 orphan-labels로 묘사되는 경고는 -w+orphan-labels로 동작하거나 -w-orphan-labels로 해지시킬 수 있다.

macro-params
 다중매크로에서 매개변수의 잘못된 수를 사용한 경우
 Enable
 
macro-selfref
 매크로가 자신을 참조하는 경우
 Enable
 
orphan-labels
 라벨 구문을 콜론 없이 사용한 경우
 Disable
 
number-overflow
 상수가 32bits를 넘어가는 경우
 Enable
 
gnu-elf-extensions
 elf 타입에서 8/16 bits 재배치를 할 경우
 Enable
 
float-overflow
 부동 소수점 타입에서 Overflow가 발생한 경우
 Enable
 
float-denorm
 부동 소수점 타입이 잘 못 된 경우
 Disable
 
float-underflow
 부동 소수점 타입에서 Underflow가 발생한 경우
 Disable
 
float-toolong
 부동 소수점 타입에서 많은 자릿수를 사용한 경우
 Enable
 

 

-v 옵션 : 버전 정보 표시

c:\>nasm -v

NASM version 2.01 compiled on Jan 17 2008

c:\>_
 


현재 사용되고 있는 NASM에 대한 버전과 컴파일된 시간을 표시한다. 버그를 보고할 때 주로 사용한다.

'구조적언어 > Asm' 카테고리의 다른 글

어셈블리 강의 자료  (0) 2009.12.20
nasm-2.07-win32.zip  (0) 2009.12.20

프로세스간에 데이터를 공유할 때..
많이 사용되는 방법중에 하나가 공유 메모리(Memory Mapped File)를 사용하는 것이다.
일단 서버에서는 읽고/쓰기 모드로 열어서 내부에서 사용하고..
다른 한쪽 혹은 여러클라이언트 에서는 읽기 전용 모드로 열어서 사용하는 가장 간편한 방법을 사용해보자.
(사용하는 방식은 메모리를 액세스하는것과 동일하다..)

 


위 그림처럼, 하나의 메모리 공간을 양쪽에서 액세스 할 수 있도록 제공해주는 점이 탁월한 장점이고,
또한 멀티 쓰레드? 멀티 코어? 와 상관없이...
서버는 읽기/쓰기 규칙을 지키고, 클라이언트는 읽기만 한다면 절대 공유 액세스 위반을 걱정할 필요가 없다.

우선 사용되는 API를 살펴보자. 아래에 해당하는 5개의 API만 사용해도 되며,
CreateFileMapping 함수의 첫번째(hFile) 인자와, 여섯번째(lpName) 인자만 주의하면 특별하게
인자에 신경쓰지 않아도 된다.

HANDLE WINAPI CreateFileMapping(
 __in          HANDLE hFile,
 __in          LPSECURITY_ATTRIBUTES lpAttributes,
 __in          DWORD flProtect,
 __in          DWORD dwMaximumSizeHigh,
 __in          DWORD dwMaximumSizeLow,
 __in          LPCTSTR lpName
);

※ HANDLE hFile
사용자가 이미 만들어 놓은 파일 핸들이나, INVALID_HANDLE_VALUE 를 전달할 수 있으며, INVALID_HANDLE_VALUE 이
전달되었을 경우는 시스템의 페이지 파일을 할당해서 사용한다.
그러므로, 특별하게 큰 파일을 사용하는 경우가 아니라면 INVALID_HANDLE_VALUE 만으로도 충분하다.

※ LPCTSTR lpName
해당 공유 메모리를 확인하기 위한 고유한 이름을 나타낸다. 일반적인 클라이언트 OS 에서는 별 문제가 없겠지만
서버 OS에 Terminal Service 가 구동중이라면 Prefix 에 따라 그 특성이 달라진다.
모든 세션에서 접근할 수 있으려면 Global\이름 과 같이 Global\ 라는 Prefix를 붙혀주어야 한다.

HANDLE WINAPI OpenFileMapping(
 __in          DWORD dwDesiredAccess,
 __in          BOOL bInheritHandle,
 __in          LPCTSTR lpName
);

LPVOID WINAPI MapViewOfFile(
 __in          HANDLE hFileMappingObject,
 __in          DWORD dwDesiredAccess,
 __in          DWORD dwFileOffsetHigh,
 __in          DWORD dwFileOffsetLow,
 __in          SIZE_T dwNumberOfBytesToMap
);

BOOL WINAPI UnmapViewOfFile(
 __in          LPCVOID lpBaseAddress
);

BOOL WINAPI CloseHandle(
 __in          HANDLE hObject
);

 

서버쪽 프로그램 파트

HANDLE hMemoryMap = NULL;
LPBYTE pMemoryMap = NULL;

hMemoryMap = ::CreateFileMapping(
    (HANDLE)0xffffffff, // 파일 맵의 핸들, 초기에 0xffffffff를 설정한다.
    NULL,        // 보안 속성
    PAGE_READWRITE,    // 읽고/쓰기 속성
    0,        // 64비트 어드레스를 사용한다. 상위 32비트 - 메모리의 크기
    sizeof(MYSTRUCT),// 하위 32비트 - 여기선LPBYTE 타입.
    L"fork_server");// 공유 파일맵의 이름 - Uique 해야한다.

if(!hMemoryMap) {
    ::MessageBox(NULL, L"공유 메모리를 생성할 수 없습니다.", L"Error", MB_OK);
    return FALSE;
}

pMemoryMap = (BYTE*)::MapViewOfFile(
    hMemoryMap,    // 파일맵의 핸들
    FILE_MAP_ALL_ACCESS,    // 액세스 모드 - 현재는 쓰기
    0,        // 메모리 시작번지부터의 이격된 상위 32비트
    0,        // 메모리 시작번지부터의 이격된 하위 32비트
    0);        // 사용할 메모리 블록의 크기 - 0이면 설정한 전체 메모리

if(!pMemoryMap)
{
    CloseHandle(hMemoryMap);
    ::MessageBox(NULL, L"공유 메모리를 열수 없습니다.",  L"Error", MB_OK);
    return FALSE;
}

__int64 check = 0;
MYSTRUCT* pStruct = (MYSTRUCT*)pMemoryMap;
while(1)
{
    pStruct->a = check;
    pStruct->b = 0.1f;
    pStruct->c = 0.0000001;
    strcpy(pStruct->buffer, "data copy");

    if(check++%100000 == 0)
    {
        if(_kbhit() != 0)
            break;
    }
}

if(pMemoryMap)
    UnmapViewOfFile(pMemoryMap);

if(hMemoryMap)
    CloseHandle(hMemoryMap);

클라이언트 프로그램 파트

HANDLE hMemoryMap = NULL;
LPBYTE pMemoryMap = NULL;

hMemoryMap = ::OpenFileMapping(FILE_MAP_READ, FALSE, L"fork_server");
if(!hMemoryMap) {
    ::MessageBox(NULL, L"공유 메모리를 생성할 수 없습니다.", L"Error", MB_OK);
    return FALSE;
}

pMemoryMap = (BYTE*)::MapViewOfFile(hMemoryMap,FILE_MAP_READ,0,0,0);
if(!pMemoryMap)
{
    CloseHandle(hMemoryMap);
    ::MessageBox(NULL, L"공유 메모리를 열수 없습니다.",  L"Error", MB_OK);
    return FALSE;
}

char buffer[64];
__int64 check = 0;
MYSTRUCT* pStruct = (MYSTRUCT*)pMemoryMap;
while(1)
{
    int a = pStruct->a;
    float b = pStruct->b;
    double c = pStruct->c;
    strcpy(buffer, pStruct->buffer);

    if(check++%100000 == 0)
    {
        if(_kbhit() != 0)
            break;
    }
}

if(pMemoryMap)
    UnmapViewOfFile(pMemoryMap);

if(hMemoryMap)
    CloseHandle(hMemoryMap);


 ShareServer.zip
 ShareClient.zip

※ 참고로, 서버프로그램이 종료되었을 경우, 클라이언트에서 메모리 맵드 파일의 현황만 가지고는 알수 없다는 단점이 있다.
즉, 서버가 죽어도 클라이언트가 살아서 데이터를 읽는데는 전혀 문제가 없기 때문에.. 이러한 부분은 별도로 확인해 주어야한다.

// ShareServer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <assert.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>

typedef struct
{
 int a;
 float b;
 double c;
 char buffer[64];

} MYSTRUCT;

int _tmain(int argc, _TCHAR* argv[])
{
 HANDLE hMemoryMap = NULL;
 LPBYTE pMemoryMap = NULL;

 hMemoryMap = ::OpenFileMapping(FILE_MAP_READ, FALSE, L"fork_server1");
 if(!hMemoryMap) {
  ::MessageBox(NULL, L"공유 메모리를 생성할 수 없습니다.", L"Error", MB_OK);
  return FALSE;
 }

 pMemoryMap = (BYTE*)::MapViewOfFile(hMemoryMap,FILE_MAP_READ,0,0,0);
 if(!pMemoryMap)
 {
  CloseHandle(hMemoryMap);
  ::MessageBox(NULL, L"공유 메모리를 열수 없습니다.",  L"Error", MB_OK);
  return FALSE;
 }

 char buffer[64];
 __int64 check = 0;
 MYSTRUCT* pStruct = (MYSTRUCT*)pMemoryMap;
 while(1)
 {
  int a = pStruct->a;
  float b = pStruct->b;
  double c = pStruct->c;
  strcpy(buffer, pStruct->buffer);

  printf("%s", pStruct->buffer);

  if(check++%100000 == 0)
  {
   if(_kbhit() != 0)
    break;
  }
 }

 if(pMemoryMap)
  UnmapViewOfFile(pMemoryMap);

 if(hMemoryMap)
  CloseHandle(hMemoryMap);
 return 0;
}

공유메모리 클라이언트 소스 이다.

// ShareServer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <assert.h>

typedef struct
{
 int a;
 float b;
 double c;
 char buffer[64];
} MYSTRUCT;

int _tmain(int argc, _TCHAR* argv[])
{
 HANDLE hMemoryMap = NULL;
 LPBYTE pMemoryMap = NULL;

 hMemoryMap = ::CreateFileMapping(
  (HANDLE)0xffffffff, // 파일 맵의 핸들, 초기에 0xffffffff를 설정한다.
  NULL,        // 보안 속성
  PAGE_READWRITE,    // 읽고/쓰기 속성
  0,        // 64비트 어드레스를 사용한다. 상위 32비트 - 메모리의 크기
  sizeof(MYSTRUCT),// 하위 32비트 - 여기선LPBYTE 타입.
  L"fork_server1");// 공유 파일맵의 이름 - Uique 해야한다.

 if(!hMemoryMap) {
  ::MessageBox(NULL, L"공유 메모리를 생성할 수 없습니다.", L"Error", MB_OK);
  return FALSE;
 }

 pMemoryMap = (BYTE*)::MapViewOfFile(
  hMemoryMap,    // 파일맵의 핸들
  FILE_MAP_ALL_ACCESS,    // 액세스 모드 - 현재는 쓰기
  0,        // 메모리 시작번지부터의 이격된 상위 32비트
  0,        // 메모리 시작번지부터의 이격된 하위 32비트
  0);        // 사용할 메모리 블록의 크기 - 0이면 설정한 전체 메모리

 if(!pMemoryMap)
 {
  CloseHandle(hMemoryMap);
  ::MessageBox(NULL, L"공유 메모리를 열수 없습니다.",  L"Error", MB_OK);
  return FALSE;
 }

 __int64 check = 0;
 MYSTRUCT* pStruct = (MYSTRUCT*)pMemoryMap;
 while(1)
 {
  pStruct->a = check;
  pStruct->b = 0.1f;
  pStruct->c = 0.0000001;
  strcpy(pStruct->buffer, "12345678901234567890\n");

  printf("%s", pStruct->buffer);

  if(check++%100000 == 0)
  {
   if(_kbhit() != 0)
    break;
  }
 }

 if(pMemoryMap)
  UnmapViewOfFile(pMemoryMap);

 if(hMemoryMap)
  CloseHandle(hMemoryMap);
 return 0;
}

공유 메모리를 이용한 서버 소스 이다. 가끔은 공유메모리를 사용할때가 있다.

+ Recent posts