리눅스 서버를 운영하다 보면 디스크의 물리적인 용량은 충분히 남아 있는데도 불구하고 새로운 파일을 생성할 수 없다는 오류 메시지를 마주하는 경우가 종종 있어요. 이런 현상은 파일 시스템 내에서 각 파일에 부여되는 고유한 식별 번호인 Inode가 모두 소모되었을 때 발생하거든요. 특히 웹 서버의 세션 데이터나 메일 큐, 캐시 파일처럼 크기는 매우 작지만 생성 개수가 방대한 데이터를 처리하는 환경에서 빈번하게 나타나는 문제입니다.

현재 시스템에 Inode가 얼마나 남아 있는지 확인하려면 df 명령어에 -i 옵션을 추가해서 실행하면 돼요. 이 명령어를 사용하면 각 파티션별로 전체 Inode의 개수와 현재 사용 중인 양, 그리고 남은 여유 공간을 퍼센트 수치로 한눈에 파악할 수 있거든요. 만약 특정 파일 시스템의 IUse% 수치가 100%에 가깝다면 해당 영역에서는 새 inode를 필요로 하는 작업, 즉 새로운 파일이나 디렉터리 생성이 막히는 상태라는 뜻이에요. 이미 존재하는 파일의 내용을 덮어쓰거나 이어쓰는 수정 작업은 블록 여유만 있다면 정상적으로 동작하거든요. 다만 vim처럼 임시 파일을 만들어 저장하는 에디터나 일부 프로그램은 새 inode를 요구하므로 실패할 수 있어요.

df -i

Inode가 부족한 파티션을 확인했다면 그다음 단계는 어떤 경로에 파일들이 비정상적으로 많이 쌓여 있는지 찾아내는 과정이에요. 단순히 ls 명령어를 사용하여 모든 파일을 나열하면 인덱싱 속도 때문에 시간이 너무 오래 걸릴 수 있으므로, find 명령어를 활용해 특정 경로 내의 파일 개수를 집계하는 방식이 훨씬 효율적이에요. 예를 들어 /tmp나 /var/lib/php/sessions 같은 경로를 집중적으로 점검하며 문제가 되는 위치를 정확히 파악해야 해요.

find /var/lib/php/sessions -type f | wc -l

원인이 되는 경로를 찾아냈다면 불필요한 파일을 삭제하거나 정리하는 조치가 필요해요. 특히 오래된 세션 정보나 만료된 임시 파일들을 주기적으로 제거해주는 cron 설정을 추가하면 이러한 문제를 예방할 수 있어요. Inode의 총 개수는 파일 시스템 생성 시 결정되거나 동적으로 할당되지만, 재부팅으로는 절대 최대 할당량이 늘어나지 않아요. 따라서 용량 부족이 발생하면 파일을 정리하는 것뿐만 아니라 필요시 파일 시스템 리사이즈나 추가 파티션 구성을 고려해야 해요.

배포나 백업 작업을 하다 보면 서버 간 파일 일관성을 맞춰야 할 때가 많거든요. 이때 자주 활용하는 명령어가 바로 rsync입니다. 단순히 cp나 scp를 쓰는 것보다 속도와 유연성이 뛰어나서 실무에서 자연스럽게 쓰게 되더라고요. 기본 사용법은 물론, 흔히 막히는 제외 규칙과 권한 유지 방법을 정리해 두면 도움이 될 것 같아요. 특히 대용량 파일을 다룰 때 전송 속도 차이는 체감 수준으로 느껴지네요.

rsync -avz --exclude='*.log' --exclude='.git/' /local/path user@remote:/remote/path

원격 호스트로 동기화할 때는 ssh 프로토콜을 연결해야 하거든요. 위 명령어에서 -a는 권한과 소유자, 수정 시간까지 그대로 유지해 주며, -v와 -z는 상세 출력과 압축 전송을 담당합니다. exclude 옵션은 따옴표로 감싸서 여러 개를 나열할 수 있어요. 만약 동기화 중 Permission denied가 뜨면 실행 사용자나 대상 디렉토리 권한을 먼저 확인해 봐야 하네요. rsync는 실제 변경이 있기 전에 --dry-run으로 시뮬레이션해 두면 실수를 방지할 수 있겠어요.

특정 패턴만 제외하고 나머지 파일만 빠르게 옮기거나 백업해야 할 때 매우 유용하게 쓰여요. 설정값이나 로그 파일처럼 포함할 대상을 명시하려면 --include 옵션과 함께 --exclude='*'를 조합하면 되네요. 경로가 길어질수록 명령이 복잡해질 수 있으니 exclude 목록은 별도로 관리해 두는 것도 좋아요. SSH 포트가 기본 22가 아니라면 -e 'ssh -p 22' 옵션을 추가해 주시면 연결이 잘 될 것 같아요.

동기화 대상에 불필요한 파일이 남아있다면 --delete 옵션을 추가하면 되네요. 하지만 이 옵션은 원본에 없는 파일을 대상에서 삭제하므로 반드시 dry-run으로 먼저 확인해야 하거든요. 실제 운영 환경에서 쓰실 때는 exclude 규칙과 함께 신중하게 적용해 봐야겠어요. 디렉토리 구조가 완전히 일치하지 않아도 변경된 파일만 차등 전송하므로 백업 효율이 매우 높아요.

운영하던 서버가 멀쩡히 돌다가 갑자기 "Too many open files"를 뱉으면서 새 요청을 못 받는 상황, 한 번쯤 겪으셨을 거예요. 저도 처음엔 파일을 몇 개 열지도 않았는데 왜 이러나 싶었거든요. 그런데 리눅스는 소켓 연결이나 파이프까지 전부 파일 디스크립터로 세더라고요. 그래서 동시 접속이 몰리는 웹 서버나 DB, 노드 앱은 생각보다 금방 한도에 부딪히는 거였어요.

원인은 대부분 프로세스별 소프트 한도가 낮게 잡혀 있어서예요. 배포판마다 다르지만 기본값이 1024인 경우가 흔하거든요. 그래서 무작정 설정을 바꾸기 전에, 지금 내 프로세스가 어떤 한도를 적용받고 있는지부터 확인하는 게 순서예요. 아래 명령들로 소프트·하드 한도와 시스템 전체 최대치를 볼 수 있어요.

# 현재 프로세스 한도 확인
ulimit -n                             # 소프트 한도 (보통 1024)
ulimit -Hn                            # 하드 한도
cat /proc/<PID>/limits | grep "open"  # 특정 프로세스의 실제 적용값
cat /proc/sys/fs/file-max             # 시스템 전체 최대치

# 1) 로그인 세션 프로세스: /etc/security/limits.conf 에 추가
#    deploy  soft  nofile  65536
#    deploy  hard  nofile  65536
#    → 다시 로그인해야 적용됨

# 2) systemd 서비스: limits.conf 를 안 봄. 서비스별로 지정
sudo systemctl edit myapp.service
#    [Service]
#    LimitNOFILE=65536   # 커널 5.15+ 는 infinity 도 가능
sudo systemctl daemon-reload
sudo systemctl restart myapp.service

확인해보고 한도가 실제로 부족하면 늘리면 되는데, 여기서 저도 한참 헤맸어요. 터미널에서 직접 띄운 프로세스는 limits.conf에 값을 넣고 다시 로그인하면 적용되거든요. 그런데 systemd로 등록해 돌리는 서비스는 이 파일을 아예 안 봐요. PAM을 거치지 않기 때문인데, 이 경우엔 systemctl edit로 서비스별 LimitNOFILE을 따로 지정해줘야 해요. 커널 5.15 이상이면 숫자 대신 infinity도 쓸 수 있고요.

한 가지 주의할 건, 한도를 무작정 올리기 전에 진짜 접속량 때문인지 아니면 파일 디스크립터 누수인지 lsof로 한 번 들여다보는 게 좋아요. 코드에서 소켓이나 파일을 안 닫고 계속 쌓고 있으면 한도만 키워봤자 시간 문제로 또 터지거든요. 저는 그걸 모르고 한도부터 올렸다가 며칠 뒤에 똑같이 뻗은 적이 있어요. 그리고 limits.conf든 systemd든 재로그인이나 서비스 재시작을 해야 반영되니 그 부분도 잊지 마세요.

참고: nixCraft - Linux Increase The Maximum Number Of Open Files (https://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/)

서버에서 디스크가 꽉 찼다는 알림을 받고 df -h를 보면 사용률이 100%인데, 정작 du로 뒤져보면 그만한 용량이 안 나오는 경우가 있거든요. 저도 처음엔 du 옵션을 잘못 준 줄 알고 몇 번이나 다시 돌려봤는데, 원인이 따로 있더라고요.

두 명령이 보는 곳이 다르기 때문이에요. df는 파일시스템이 실제로 잡고 있는 블록을 커널 수준에서 읽고, du는 디렉터리를 하나씩 걸어다니면서 눈에 보이는 파일 크기를 더합니다. 그래서 디렉터리 엔트리는 사라졌는데 블록은 아직 잡혀 있는 파일이 생기면 둘이 어긋나요. 가장 흔한 게 커다란 로그 파일을 rm으로 지웠는데 그 파일을 열고 있던 프로세스가 아직 살아 있는 경우입니다. rm은 링크만 끊을 뿐이라, 프로세스가 파일 디스크립터를 놓지 않으면 커널은 그 블록을 반환하지 않거든요. du 눈에는 안 보이는데 df만 계속 꽉 차 있는 상태가 되는 겁니다.

이런 파일은 lsof +L1로 찾을 수 있어요. 링크 수가 1 미만인 파일, 그러니까 지워졌는데 아직 열려 있는 파일만 골라서 보여줍니다.

# 지워졌지만 아직 열려 있는 파일 찾기 (크기순 정렬)
lsof +L1 | sort -k7 -rn | head

# 해당 프로세스를 재시작하면 커널이 블록을 반환한다
sudo systemctl restart nginx

# 재시작이 곤란할 때: fd를 통해 내용만 비운다 (로그 파일 한정)
: > /proc/1234/fd/3

# inode 고갈 여부 확인
df -i

가장 확실한 해결책은 그 파일을 붙잡고 있는 프로세스를 재시작하는 거예요. 프로세스가 파일 디스크립터를 닫으면 커널이 블록을 반환하고, df 수치가 바로 내려갑니다. 재시작이 곤란한 상황이라면 /proc/PID/fd/N 경로로 파일 내용만 잘라내는 방법도 있는데, 이건 날려도 되는 로그 파일에만 쓰세요. DB의 WAL처럼 복구에 쓰이는 파일에 하면 데이터가 깨질 수 있습니다.

그리고 df -h로 보면 여유가 있는데 "No space left on device"가 뜬다면 이건 다른 문제일 가능성이 큽니다. inode 고갈이거든요. df -i로 IUse%를 확인해보고 100%에 가깝다면, 작은 파일이 수십만 개씩 쌓인 디렉터리를 찾아 정리해야 해요. 세션 파일이나 캐시가 쌓이는 디렉터리가 주범인 경우가 많더라고요.

정리하면 df와 du가 안 맞을 땐 lsof +L1, 용량은 남았는데 못 쓸 땐 df -i. 이 두 개만 기억해두면 대부분의 디스크 풀 상황은 몇 분 안에 풀립니다.

서버 하나 띄우려는데 "Address already in use" 라고 뜨면서 안 올라올 때 있잖아요. 저도 로컬에서 8080 포트를 이미 누가 잡고 있어서 몇 번이나 당황했거든요. 이럴 때 어떤 프로세스가 그 포트를 물고 있는지 찾아서 정리하는 방법을 정리해봤어요. 알고 나면 별거 아닌데, 모르면 매번 재부팅하게 되더라고요.

먼저 포트를 쓰는 프로세스를 찾아야 하는데, 저는 보통 lsof를 제일 먼저 써요. lsof -i :8080 이렇게 치면 그 포트를 쓰는 프로세스랑 PID가 바로 나오거든요. 요즘 서버엔 netstat이 아예 안 깔려 있는 경우도 많은데, 그럴 땐 ss가 대체제라서 편해요. ss -tulnp | grep 8080 하면 리스닝 중인 소켓이랑 PID가 나와요. netstat이 있는 환경이면 netstat -tulnp | grep :8080 도 똑같이 됩니다.

PID를 확인했으면 종료는 간단해요. kill PID 로 정상 종료 신호(SIGTERM)를 보내는 게 기본이고요. 이걸로 안 죽고 버티면 그때 kill -9 PID 로 강제 종료하면 됩니다. 근데 PID 찾는 것도 귀찮다 싶으면 fuser -k 8080/tcp 한 방으로 그 포트 쓰는 프로세스를 바로 죽일 수도 있어요. 급할 때 저는 이거 자주 씁니다.

주의할 점 하나는, kill -9는 프로세스가 뒷정리할 틈도 없이 끊어버리는 거라 저장 안 된 데이터가 날아갈 수 있어요. 그래서 웬만하면 그냥 kill 먼저 써보고, 정 안 되면 -9로 가는 걸 추천해요. 그리고 남의 프로세스나 시스템 프로세스면 sudo가 필요할 수 있으니 권한 없다고 나오면 sudo 붙여서 다시 해보시면 됩니다.

현재 로그인한 계정의 홈폴더 (~)에 ".vimrc" 파일 생성 후 아래 내용 저장

set fileencodings=utf-8,euc-kr
set encoding=utf-8

출처:http://egloos.zum.com/indirock/v/3791689

[vi 에디터 utf8 <-> euc-kr 웹문서 encoding 전환하기]
원문: (http://onlyu.blog.me/60123862837)

 

vi로 웹문서를 열어 보면 한글이 깨어져 있고

<meta http-equiv=Content-Type Content="text/html; charset=euc-kr">이 보인다면

리눅스 콘솔창에 env 해 볼때 LANG=ko_KR.UTF-8 으로 나온면 utf8 환경입니다.

 

Q) 그럼 한글이 깨어져 보이는 utf-8 시스템 환경에서 euc-kr 웹문서를 제대로 볼 수 없는 것인가?

A) 리눅스 환경이라면 vi 환경설정 파일인 .vimrc 파일 set fileencodings=utf8,euc-kr 를 추가하면 문서를 열때 자동적으로 fileencoding이 utf8인지 euc-kr 인지 encoding에 맞게 열고 저장을 합니다.

계정 로그아웃(재접속)하지 않고 vi 설정을 적용할려면 콘솔에서 source .vimrc 하고 엔터키를 누르면 됩니다.

 

Q) 그럼 euc-kr 파일 웹문서를 utf8 파일로 변경을 하고 싶다면 어떻게 하죠?

A) vi로 파일을 열고 나서

:set fileencoding=utf-8

:w

 

하면 됩니다. 저장 후 종료를 할려면 :wq 엔터를 하면 됩니다.

반대로 utf8 문서를 euc-kr로 변경 할려면 :set fileencoding=euc-kr을 하면 됩니다.

 

 

euc-kr 웹문서를 utf8로 변경 하고 저장 했다면

<meta http-equiv=Content-Type Content="text/html; charset=utf-8">

로 하지 않으면 웹브라우저에서 확인시에는 다시 한글이 깨어져 보이겠죠.

 

 

 

 

 

Q) vi 에디터로 열지 않고 euc-kr 웹문서를 utf8로 변경 할려고 합니다. 어떻게 해야 하죠?

 

A) iconv 명령어로 가능합니다.

 

iconv -f euc-kr -t utf-8 euc-kr.html --output utf8.html

 

or 

 

iconv -f euc-kr -t utf-8 euc-kr.html > utf8.html

 

 

 

Q)한개 파일이 아니라 여러개의 html 파일을 동시에 변경 할려면 어떻게 하죠?

 

백업 파일처럼 utf8.html로 할 필요없이 그냥 utf-8 파일로 변환 되면 좋겠는데요??

 

A)

 

변경을 원하는 경로로 이동을 하고 아래와 같은 명령어로 한방에 그럼 변경해 보겠습니다.

 

cd /web/files 

 

for I in ./-.html ; do iconv -c -f euc-kr -t utf-8 $I > $I.tmp && mv $I.tmp $I ; done

 

 

 

작업 완료 전에는 무조건 백업본을 유지하는 것이 좋습니다. 그냥 원본폴더를 tar로 묶어 두면 되죠. 

 

시스템 환경에 따라 작업 환경에 따라 charset encoding은 테스트 작업을 하고 본격적으로 진입 하는 것이 바람직합니다.  

 

 

 

Q) recode 명령어로 한번에 변경 할 수 있다고 하는데 어떻게 하나요?

 

A) 먼저 시스템에 recode 명령어를 사용할 수 있는지 확인 해야 하는데

 

rpm -qi recode 해서 아무것도 안나오면 설치 해야합니다.

 

yum install recode recode-devel 또는 rpm을 찾아서 설치 하거나 

 

http://recode.progiciels-bpi.ca/index.html 접속해서 파일을 받아서 설치합니다.

 

recode 명령어로 얼마나 많은 charset 변경을 할 수 있는지 확인은

 

recode -l 로 살펴 보면 됩니다. 그럼 euc-kr에서 utf-8로 변경 명령어는 아래와 같습니다.

 

 

 

recode -v <소스 CHARSET>...<변환 CHARSET> <파일명>

 

recode -v EUC-KR...UTF-8 *.html

 

 

 

 

 

Q) php에서 특정 문자열만 euc-kr 또는 utf8로 할려면 어떻게 하죠?

 

A) iconv 함수를 이용하면 됩니다.

 

iconv("euc-kr", "utf-8", $str); // euc-kr을 utf8로 encoding 됩니다.

 

iconv("utf-8", "euc-kr", $str); // utf8을 euc-kr로 encoding 됩니다.

 

참조 URL : http://www.php.net/manual/en/function.iconv.php

 

 

 

 

 

Q) java,jsp에서 문자열 encoding 전환은?

 

A)

 

StringBuffer szBuffer = new StringBuffer();
String str = new String(szBuffer.toString().getBytes("UTF-8"), "EUC-KR");

 

http://download.oracle.com/javase/1.5.0/docs/guide/intl/encoding.doc.html

 

여전히 한글이 깨어진다면 아래 상황을 체크 해 봅니다.

 

1. <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

 

2. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

 

3. <Connector URIEncoding="UTF-8" connectionTimeout="10000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
4. URIEncoding 세팅을 해 놓아도 get/post 메소드로 넘어갈때 Parameter값 한글이 깨어질때는

 

SetCharacterEncodingFilter.java 파일을 $CATALINA_HOME/common/classes (톱캣) 또는 WEB-INF/classes (개인환경) 밑에

 

javac SetCharacterEncodingFilter.java -d .

 

컴파일을 하고 web.xml 파일 encoding 필터 세팅이 되어 있는지 확인 해 봅니다.

 

* utf8 톰캣이 아니라면 톰캣 4.x 은 기본적으로 8859_1로구동이 됩니다. export LANG=en_US.iso8859-1

 

export LANG=ko_KR.eucKR 으로 한다면 charset은 euc-kr로 구동이 됩니다.

 

추가 옵션으로 export CATALINA_OPTS='-Dencoding.default=euc-kr -Dfile.encoding=euc-kr'

 

 

 

 

 

Q) 윈도우 노트패드(notepad)에서 encoding 변환 작업은 할 수 없나요?

 

A) 윈도우에서 작업 가능한 무료 에디터 notepad++를 소개 해 드립니다.

 

http://notepad-plus-plus.org/ 접속 후 다운로드(DOWNLOAD) 메뉴에서 받으시면 됩니다.

 

윈도우에서 생성한 ANSI Encoding 파일을 상단 메뉴 Encoding 에서

 

Convert to UTF-8 without BOM (UTF-8 형식으로 변환 BOM 없음) 으로 선택하시면 UTF-8 Charset 으로 변환이 됩니다.

 

 




 

(notepad++ 메뉴를 한글로 변경 Settings > Preferences > General Localization 셀렉터 항목에 한국어를 선택하면 됩니다.)

 

 

 


(추가)

 

Q) 여러 사이트에서 넘어 오는 값이 각각 다른데 utf8 인지 euc-kr 인지 어떻게 알죠?

 

A) php 경우라면 mb_detect_encoding($str); 로 찍어 보면 압니다.

 

하여 각각 원하는 encoding을 iconv로 변환을 해 주면 됩니다.

curl -o /dev/null -w "Connect: %{time_connect} TTFB: %{time_starttransfer} Total time: %{time_total} \n" [체크할 URL]

'develop > linux' 카테고리의 다른 글

vi 자동으로 encoding 설정  (0) 2024.03.07
vi euc-kr, utf-8  (0) 2019.12.24
GNU C, __attribute__  (0) 2014.10.14
Linux C에서 키보드 이벤트 받기(kbhit())  (0) 2014.02.28
NAT 종류별 설정  (0) 2014.02.17

출처: http://blog.daum.net/english_100/5


GNU C의 커다란 특성(초보자가 알기 쉽지 않지만) 중 하나는 속성(__attribute__)체계이다. __attribute__는 함수속성(Function attribute) 변수속성(Variable attribute) 그리고 타입속성(Type attribute)로 구분 된다. __attribute__의 표현 방식은 attribute의 앞과 뒤에 각각 두개씩의 아래바(__)를 붙이고 바로 이어 괄호안에 속성 인자를 쓰도록 되어있다.

 

 

1. 함수속성 (Function Atrribute) 

참조 : http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Function-Attributes.html#Function-Attributes

 

GNU C에서 프로그램에서 불리워질 함수들에 대해 컴파일러로 하여금 더욱 주의하여 최적화하고 검사하도록 선언할 수 있다. __attribute__는 우리가 함수를 선언할 때 특별한 속성을 부여할 수 있다. 이 __atribute__ 다음에는 쌍괄호로 싸여진 속성인자가 따라온다.

우리는 다음의 속성 키워드의 앞뒤에 __을 붙여 사용할 수 있다. 이는 같은 이름으로 정의된 매크로들에 상관없이 헤더파일에서 이 키워드들을 사용할 수 있게 해준다.


alias ("target")

alias 속성은 함수의 선언이 이미 명기된 다른 심볼에 대한 알리아스를 발생하도록 한다. 예를 들어,

void __f() { /* Do something. */ ; }

void f() __attribute__((weak, alias("__f")));

'f'를 '__f'에 대한 약한 알리아스로 정의한다.

 

aligned(alignment)

이 속성은 함수에 대한 최소정렬을 바이트 단위로 명기한다.

함수의 정렬을 감소시키기 위해 이 속성을 사용할 수 없고 단지 증가를 위해서만 사용가능하다. 하지만 함수에 대한 정렬을 명기했을 경우 -falign-functions 옵션의 효력은 사라지게 된다.

aligned 속성에 의한 효과는 링커(linker)에 의해 제한될 수 있다. 많은 시스템에서 함수는 링커가 제공하는 최대 정렬값까지 정렬될 수 있다. (어떤 링커는 최대 정렬값이 매우 매우 매우 작다.) aligned 속성은 변수에도 사용될 수 있다. (Variable Attribute 참조)

 

alloc_size

always_inline

gnu_inline

artifical

bank_switch

flatten

error("message")

warning("message")

 

cdecl

인텔 386 시스템에서 cdecl 속성은 컴파일러로 하여금 함수 인자를 전달하기 위해 사용했던 스택공간을 호출함수가 정리(pop off)할 것으로 가정하게 한다. 이는 -mrtd 스위치 효과를 덮어씌우기 위해 사용될 수 있다.

 

const

constructor

destructor

constructor(priority)

destructor(priority)

deprecated

deprecated(msg)

disinterrupt

dllexport

dllimport

eightbit_data

exception_handler

externelly_visible

far

fast_interrupt

 

fastcall

인텔 396 시스템에서 fastcall 속성은 컴파일러로 하여금 함수의 첫째 인자는 ECX를 통해 두 번째 인자는 EDX를 통해 전달하게 한다. 이어지는 더 많은 인자들은 스택을 통해 전달한다. 스택의 인자값들은 호출된 함수에서 정리(pop off) 한다. 만약 함수에 전달되는 인자수가 가변적이라면 모든 인자들은 스택을 통해 전달된다.

 

thiscall

인텔 386 시스템에서 thiscall 속성은 컴파일러로 하여금 함수의 첫째 인자는 ECX를 통해 전달하게 한다. 이어지는 다른 인자들은 스택을 통해 전달한다. 스택값은 호출된 함수에서 정리(pop off)된다. 전달되는 함수 인자 수가 가변적이면 모든 인자들은 스택을 통해 전달된다. thiscall 속성은 C++ non-static member 함수를 위한 것이다.

 

format( archetype, string-index, first-to-check )

format 속성은 함수가 printf, scant, strftime, strfmon 등과 같은 함수 인자 스타일을 갖음을 명기함으로써 포맷 문자열에 대해 typecheck가 이루어지게 한다. 예를 들어

extern int

my_printf(void *my_object, const char *my_format, ... )

__attribute__((format (printf, 2, 3)));

        

위 선언은 컴파일러로 하여금 my_printf를 호출하기 위해 함수인자인 my_format이 printf 형식의 포맷 문자열로서 모순이 없는지를 체크하게 한다.  

파라메터 archetype은 포맷 문자열을 해석할 방식을 결정하는데 printf, scant, strftime, gnu_printf, gnu_scanf, gnu_strftime, strfmon 중에 하나이어야 한다. 파라메터 string-index는 어떤 함수인자가 포맷 문자열인지를 가리키며 first-to-check는 문자열에 대해 체크해 나갈 첫 함수인자의 번호이다. 한가지 용례로 아래의 test.c 프로그램을 보자.

1:

2: extern void myprint(const char *format, ...) __attribute__((format(print, 1, 2)));

3:

4: void test()

5:{

6:      myprint("%d\n", 4);

7:      myprint("%s\n", 4);

8:      myprint("%s\n", "abc");

9:      myprint("%s %d %d\n", 4, 6);

10:}

$gcc -Wall -c test.c test를 수행하면 다음과 같은 경고가 나타난다.

test.c: In function 'test'

test.c:7: warning: format '%d' expects type 'int', but argument 2 has type 'char *'

test.c:9: warning: format '%s' expects type 'char *', but argument 2 has type 'int'

test.c:9: warning: toot few arguments for format

만약 함수 선언중 _attribute__(()) 부분을 없애버리면 위의 경고문구는 사라지게 된다.


 

format_arg(string-index)

function_vector

interrupt

ifunc

interrupt_handler

interrupt_thread

isr

kspisusp

l1_text

l2

leaf

long_call/short_call

longcall/shortcall

long_call/near/far

malloc

mips16/nomips16

model(model-name)

ms_abi/sysv_abi

callee_pop_aggregate_return(number)

ms_hook_prologue

naked

near

nesting

nmi_handler

no_instrument_function

no_split_stack

noinline

noclone

nonull(arg-index, ...)

 

noreturn

abort 나 exit 같은 몇몇 표준 라이브러리 함수들은 반환할 수 없다. GCC는 자동으로 이를 안다. 어떤 프로그램들은 함수가 반환하지 않음을 자체적으로 정의할 수 있다. 우리는 noreturn을 선언함으로써 이를 컴파일러에게 일러줄 수 있다.

void fatal() __attribute__((noreturn));

void fatal( /* ... */ )

{

/* ... */ /* Print error message. */ /* ... */

exit(1);

}

noreturn 키워드는 컴파일러에게 fatal 함수가 반환할 수 없음을 일러준다. 그러면 이 fatal 함수가 무엇을 반환하려 하든 관계없이 최적화할 수 있다. 이는 조금 나은 코드를 만들게 하며 더 중요한 것은 초기화되지 않은 변수들에 대해 애매한 경고를 하지 않게 한다.

noreturn 함수가 void 이외의 타입을 갖는 것은 더 이상 의미가 없게 된다.

 

nothrow

optimize

pcs

pure

hot

cold

 

regparm(number)

인텔 386 시스템에서 regparm 속성은 컴파일러로 하여금 첫 번째 함수 인자로부터 number 번째 인자를 스택이 아닌 EAX, EDX ECX 등의 레지스터를 통해 전달하게 한다.

 

sseregparm

force_align_arg_pointer

resbank

return_twice

saveall

save_volatiles

section("section-name")

컴파일러가 생성한 코드는 text 영역에 두는 것이 정상적이다. 그러나 종종 추가적인 영역이 필요하거나 특별한 영역에 두어야 할 특별한 함수를 갖게 되는 경우가 있다. section 속성은 임의의 함수가 특정 영역에 있어야 함을 명기한다. 예를 들어

extern void foobar(void) __attribute__((section("bar")));

와 같이 선언하면 이는 함수 foobar를 bar 영역에 두라는 이야기이다.

어떤 파일형식은 임의의 영역을 지원하지 않으므로 section 속성은 모든 플랫폼에서 이용가능한 것은 아니다. 만약 한 모듈의 모든 내용을 하나의 영역에 두고자 한다면 링커를 이용할 수도 있다.

 

sentinel

short_call

shortcall

signal

sp_switch

 

stdcall

인텔 386 시스템에서 stdcall 속성은 컴파일러로 하여금 함수인자가 가변 개수가 아닌 이상은 인자를 전달하기 위해 사용한 스택영역을 호출된 함수에서 정리(pop off) 하는 것으로 가정하게 한다.

 

syscall_linkage

target

tiny_data

trap_exit

unused

used

version_id

visibility

vliw

warn_unused_result

weak

weakref

weakref("target")


 

 

    

2. 변수속성 (Variable Attribute)

참조 : http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Variable-Attributes.html#Variable-Attributes

 

 

3. 타입속성 (Type Attribute)

참조 : http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Type-Attributes.html#Type-Attributes

 


'develop > linux' 카테고리의 다른 글

vi euc-kr, utf-8  (0) 2019.12.24
TTFB 체크 명령어  (0) 2016.02.16
Linux C에서 키보드 이벤트 받기(kbhit())  (0) 2014.02.28
NAT 종류별 설정  (0) 2014.02.17
Linux TCP/IP tunning  (0) 2014.01.08

출처: http://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input


windows에서 conio.h를 포함하고 _kbhit()함수를 사용하여 키보드 이벤트가 발생했는지 여부를 알 수 있는데 리눅스에서는 해당하는 함수가 없어서 검색해봄.


#ifndef WIN32

int _kbhit()

{

struct timeval tv = { 0L, 0L };

fd_set fds;

FD_ZERO(&fds);

FD_SET(0, &fds);

return select(1, &fds, NULL, NULL, &tv);

}

#endif



위의 소스로 안되는 경우가 있어서 좀 더 찾아보니 다음과 같은 것들도 있다.

출처는 linux kbhit 오픈 소스라는데... 까먹음 ;;


static struct termios initial_settings, new_settings;

static int peek_character = -1;


void init_keyboard()

{

tcgetattr(0,&initial_settings);

new_settings = initial_settings;

new_settings.c_lflag &= ~ICANON;

new_settings.c_lflag &= ~ECHO;

new_settings.c_cc[VMIN] = 1;

new_settings.c_cc[VTIME] = 0;

tcsetattr(0, TCSANOW, &new_settings);

}


void close_keyboard()

{

tcsetattr(0, TCSANOW, &initial_settings);

}


int _kbhit()

{

unsigned char ch;

int nread;


if (peek_character != -1) return 1;

new_settings.c_cc[VMIN]=0;

tcsetattr(0, TCSANOW, &new_settings);

nread = read(0,&ch,1);

new_settings.c_cc[VMIN]=1;

tcsetattr(0, TCSANOW, &new_settings);

if(nread == 1) 

{

peek_character = ch;

return 1;

}

return 0;

}


int _getch()

{

char ch;


if(peek_character != -1) 

{

ch = peek_character;

peek_character = -1;

return ch;

}

read(0,&ch,1);

return ch;

}


int _putch(int c) {

putchar(c);

fflush(stdout);

return c;

}


사용법


init_keyboard();

while (1) {

if (_kbhit()) {

int ch = _getch();

_putch(ch);

switch (ch) {

...

}

}

}

close_keyboard();



putch를 해주는 이유는 _getch호출 시 화면에 출력하지 않고 바로 input buffer에서 읽어오기 때문에 사용자에게 보여주기 위해 출력해줌.

'develop > linux' 카테고리의 다른 글

TTFB 체크 명령어  (0) 2016.02.16
GNU C, __attribute__  (0) 2014.10.14
NAT 종류별 설정  (0) 2014.02.17
Linux TCP/IP tunning  (0) 2014.01.08
Ubuntu에서 Oracle java 설치  (0) 2013.12.31

+ Recent posts