프로그래밍/C2013. 11. 23. 23:29

Level Symbol Description Associativity
1 ++
--
( )
[ ]
->
.
Prefix increment
Prefix decrement
Function call and subexpression
Array subscript
Structure pointer
Structure member
left to right
2 !
~
-
+
(type)
*
&
sizeof
Logical negation
1's complement
Unary negation
Unary plus
Type cast
Pointer dereference
Address of
Size of
right to left
3 *
/
%
Multiplication
Division
Modulus (integer remainder)
left to right
4 +
-
Addition
Subtraction
left to right
5 <<
>>
Bitwise left shift
Bitwise right shift
left to right
6 <
<=
>
>=
Less than
Less than or equal to
Greater than
Greater than or equal to
left to right
7 ==
!=
Equal test
Not equal test
left to right
8 & Bitwise AND left to right
9 ^ Bitwise exclusive OR (XOR) left to right
10 | Bitwise inclusive OR left to right
11 && Logical AND left to right
12 || Logical inclusive OR left to right
13 ?: Conditional test right to left
14 =
+=
-=
*=
/=
%=
<<=
>>=
&=
^=
|
Assignment
Compound add
Compound subtract
Compound multiply
Compound divide
Compound modulus
Compound bitwise left shift
Compound bitwise right shift
Compound bise AND
Compound bitwise exclusive OR
Compound bitwise inclusive OR
right to left
15 ,
++
--
Sequence point (list separator)
Postfix increment
Postfix decrement
left to right

Posted by code cat
프로그래밍/C2013. 11. 19. 22:57

typedef struct g_struct {

  int value;

  struct g_struct *next;  //OK

  //gStruct *next  //WRONG!

} gStruct;



알겠지만, 적어도 C에서는 typedef struct 정의 안에서 typedef 된 개체 자체를 reference할 수 없다. 

'프로그래밍 > C' 카테고리의 다른 글

[visual studio] 에러 C2143 로컬변수 선언 위치  (0) 2013.11.24
c precedence table  (0) 2013.11.23
symbol visibility  (0) 2013.08.07
typedef 와 static 을 동시에 사용 못하는 이유  (0) 2012.11.24
인라인 어셈블리  (0) 2012.09.25
Posted by code cat
프로그래밍/C2013. 8. 7. 21:36

출처: http://www.technovelty.org/code/why-symbol-visibility-is-good.html

 

ELF 는 프로그램의 심볼을 관리하는데 있어서 두가지 방법이 있는데, 그중 하나가 symbol binding 이다.

symbol binding에는 크게 다음의 두가지 종류가 있다.

 

1. Global binding

2. Local binding

 

Global 바인딩은 현재 빌드되는 file 밖에까지의 visibility scope을 가지고 있다.(즉 외부참조가 가능하다고 할 수 있겠다)

Local 바인딩은 반대로 local scope(static)을 가지고 있다.  추가로 weak의 경우 global가 같으나 overriding이 가능하다고 볼 수 있겠다.

 

다음의 예를 보자.

sym.c


컴파일 해보면,(참고로 gcc -c는 컴파일/어셈블은 하되, 링크는 하지 말라는 소리이다)

$ gcc -o sym -c sym.c

$ readelf -s sym
 Symbol table '.symtab' contains 11 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
...
     5: 00000000     6 FUNC    LOCAL   DEFAULT    1 local
     8: 00000006     6 FUNC    GLOBAL DEFAULT    1 global
     9: 0000000c     6 FUNC    WEAK    DEFAULT    1 weak

 

위에서 말한 바와 같이 LOCAL, GLOBAL, WEAK으로 각각 분류된 것을 볼 수 있다.

 

다음의 경우를 보자.

 

This is all well and good, but starts breaking down when you want to load many different modules and keep strict API's (such as, say, dynamic libraries!).

Consider that for two files to share a common function, the function must end up with a global visibility.

file1.c

 

file2.c

file1 & file2는 같은 함수를 공유 하는데, 보면 알겠지만 common의 경우 함수 내부에서만 사용되고 있어, 외부로 노출 할 필요가 없는 함수이다.

 

컴파일 후 내용을 보면 다음과 같다.

$ gcc -shared -fPIC  -o libfile file1.c file2.c
$ readelf --syms libfile

 

Symbol table '.symtab' contains 55 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
...
    48: 000005fc    6   FUNC    GLOBAL DEFAULT   12 common
    50: 00000604    11 FUNC    GLOBAL DEFAULT   12 func

앞서 말했듯이, common의 경우 외부로 노출할 필요가 없음에도 GLOBAL 바인딩되어 있는 것을 볼 수 있다.

링킹도 잘 되고 동작성에 문제 없으나, 이렇게 외부로 노출 될 필요가 없는 경우를 대비해 ELF는 심볼에 대한 visibility를 제공한다.

이 visibility에는 default, protected, hidden 혹은 internal이 있다.

 

가장 안전한 방법으로는 전부 hidden으로 세팅하고(-fvisibility=hidden) 필요 시에,

file1.c

file2.c

 

 

$ gcc -fvisibility=hidden -shared -fPIC  -o library file1.c file2.c
$ readelf --syms ./library

Symbol table '.symtab' contains 55 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
    48: 000003cc     5 FUNC    LOCAL  HIDDEN   12 common
    54: 000003d4    29 FUNC    GLOBAL DEFAULT  12 func

 

 

이렇게 되면 dynamic loader는 더 이상 common쪽에 접근을 허용치 않는다.

참고로 이러한 방식은 퍼포먼스 향상에도 도움을 준다.  보통 심볼이 override됐을 때, dynamic loader가 function을 제대로 가리킬 수 있도록 컴파일러는 program lookup table(PLT)를 생성해야 한다.  그러나 위와 같이 한다면 PLT 생성을 생략 할 수 있다.

Posted by code cat
프로그래밍/C2012. 11. 24. 11:13

결론부터 말하면, typedef 과 static은 storage class이기 때문에, 둘다 동시에 사용 못한다.

(우리가 변수를 int와 long으로 동시에 선언하지 못하듯이 말이다.)

 

또한 typedef은 변수를 instance화 시키는게 아니라, type을 선언하는 것이다.  반면에 static은 instance에 적용된다.

'프로그래밍 > C' 카테고리의 다른 글

typedef struct 안에서 스스로를 참조 할 때 주의점  (0) 2013.11.19
symbol visibility  (0) 2013.08.07
인라인 어셈블리  (0) 2012.09.25
include guard에 대해서  (0) 2012.09.24
구조체 초기화 방법  (0) 2012.08.21
Posted by code cat
프로그래밍/C2012. 9. 25. 09:15

    인라인 어셈블리



    1. #if __LINUX_ARM_ARCH__ >= 6

    2. static inline unsigned long arch_local_irq_save(void)

    3. {

    4. unsigned long flags;

    5. asm volatile(" mrs %0, cpsr    @ arch_local_irq_save\n"

    6. "            cpsid i"

    7. : "=r" (flags) : : "memory", "cc");

    8. return flags;

    9. }


 인라인 어셈블리에 대해서 간단히 짚고 넘어가자. 나중에 보면 이해가 안될거 같으니까.

보통 다음과 같은 문법이다.

__asm__ __volatile__ (asms : output: input: clobber);

ANSI에서는 __asm__만 쓰니까, asm 보단 __asm__을 쓰는게 낫다.  volatile(__volatile__)은 최적화를 진행하지 않는다.  컴파일러가 괜히 머리 쓴다고 사용되지 않는다고 판단되는 변수를 없애는 불상사를 방지한다.

asm은 따옴표로 둘러싸인 어셈블리 코드(여기서는 "mrs ... cpsid i"가 되겠다)이며, %와 같은 형태로 input, output parameter를 사용할 수 있다.  컴파일 후, 파라미터가 치환된 대로 어셈블리 코드로 나타난다.

output은 결과값을 출력하는 변수이다. 

"=r"(flags)이다. =는 쓰기전용이란 뜻이다.

input은 output과 같은 방식으로 사용하고, 인라인 어셈블리 코드에 넘겨주는 parameter를 적는다.

clobber는 asm를 실행 시, 값이 변하는 것을 적어준다.  각 변수는 쉼표로 구분되며 각각을 따옴표로 감싸준다. "memory", "cc"가 되겠다.

이제 실제 코드를 분석해 보면,

mrs %0, cpsr 에서는 "=r" (flags)에서, 레지스터 넘버를 flags로 받은 뒤 나오는 레지스터로 cpsr를 저장시킨다. 그 후 cpsid i를 통해 인터럽트를 disable 시킨다. cpsid i는 arm cortex에서 인터럽트를 disable 시킨다. armv7 전용 명령어로 알고 있었는데, ifdef에서 version 6부터 체크하는 걸 보니, armv6에서도 가능한가 보다.

clobber 영역의 "memory"는 컴파일러에게 어셈브릴 코드가 메모리의 어딘가를 변경한다고 가르쳐 주는 것이다. 만약 이렇게 안해주면 컴파일러는 어셈블리코드에서 메모리의 내뇽을 변경하는 것을 컴파일러는 전혀 알 수 없다. "memory"를 명시해 주면, 컴파일러는 어셈블리 코드를 실행하기 전/후에 레지스터에 저장되어 있는 모든 변수의 값을 갱신하도록 한다. "cc"는 컴파일러에게 어셈블리 명령어가 컨디션 코드 플래그를 읽고 쓴다고 알려준다.  설명이 길어졌다. 결국, cpsr를 저장하고 인터럽트를 disable 시킨다.

'프로그래밍 > C' 카테고리의 다른 글

symbol visibility  (0) 2013.08.07
typedef 와 static 을 동시에 사용 못하는 이유  (0) 2012.11.24
include guard에 대해서  (0) 2012.09.24
구조체 초기화 방법  (0) 2012.08.21
error: expected identifier before numeric constant  (0) 2012.07.03
Posted by code cat
프로그래밍/C2012. 9. 24. 13:58

include guard란 실수로 인해 같은 header 파일이 한번 이상 include되는 걸 막는 방법이다.


아래 예제를 보자.


basic.h


intermediate.h


expert.c


보는 바와 같이 expert.c에서 basic.h를 두번 include하는 결과가 되었다. (라인1에서 한번, 라인 2의 intermediate.h는 결국 basic.h를 include한다)


그래서 이러한 상황을 막기 위해 헤더파일을 정의 할 때 다음과 같이 basic.h에 중복 정의를 막는 매크로를 사용한다.

basic.h  (modified)

 

이러한 예제만 보면 별거 아닌거 가지고 저러나 싶겠지만, 파일 수십가지 수백가지가 되면 의도치않게 중복으로 include하게 된다.

Posted by code cat
프로그래밍/C2012. 8. 21. 18:51

출처: http://kldp.org/node/71304

typedef struct aa = {
    int a;
    int b;
}AA;
 
/* 1번 방법 */
AA a = {
    1,
    2
};
 
/* 2번 방법 */
AA b = {
    .a = 1,
    .b = 2
};
 
/* 3번 방법 */
AA c = {
    a:1,
    b:2
};

1은 ANSI 표준, 2는 ISO C (C99) 표준, 3은 GCC 확장 기능입니다.

'프로그래밍 > C' 카테고리의 다른 글

인라인 어셈블리  (0) 2012.09.25
include guard에 대해서  (0) 2012.09.24
error: expected identifier before numeric constant  (0) 2012.07.03
정적 라이브러리, 동적 라이브러리 만들기  (0) 2012.04.04
sprintf 사용법  (0) 2012.04.03
Posted by code cat
프로그래밍/C2012. 7. 3. 17:19

error: expected identifier before numeric constant


위와 같은 에러가 나는 이유

1. include로 헤더파일을 추가했는데 어디선가 같은 이름의 매크로가 꼬였을 때,

해결책 --> (에러 나는 라인의 매크로로 grep을 잡아보자!)


'프로그래밍 > C' 카테고리의 다른 글

include guard에 대해서  (0) 2012.09.24
구조체 초기화 방법  (0) 2012.08.21
정적 라이브러리, 동적 라이브러리 만들기  (0) 2012.04.04
sprintf 사용법  (0) 2012.04.03
sscanf 사용법  (0) 2012.03.28
Posted by code cat
프로그래밍/C2012. 4. 4. 14:25

정적 라이브러리

컴파일 시 링커로 라이브러리의 오브젝트 코드를 만들고자 하는 타겟 바이너리에 추가된다.

동적 라이브러리

컴파일 시, 라이브러리가 사용된 곳에 공유 라이브러리를 쓴다고 해놓고, 런타임시 동적링크로 링크한다.

 

 

정적 라이브러리 만들기

언제나와 같이 예제로 살펴보자.
우선 foo1.c라는 파일을 하나 만들어 다음과 같이 넣어보자.

자 이제는 foo2.c를 만들어 다음과 같이 만들자.

마지막으로 이 둘을 interface해 줄 역활의 foolib.h을 만들자.

 

코드 입력을 다 끝냈으면 이제 foo1.c와 foo2.c를 컴파일 하자.

gcc -c foo1.c foo2.c

 

그러면 foo1.o 와 foo2.o라는 오브젝트 파일이 만들어지는데, 이 둘을 다음과 같이 묶어주자.

ar rscv libfoo.a foo1.o foo2.o

 

그러면 libfoo.a라는 파일이 생성된다.  이 파일이 이제 우리가 쓸 수 있는 정적라이브러리 파일이다. 제대로 동작하나 보기 위해, example.c를 만들자.

 

컴파일은 다음과 같이 한다.

gcc -o example example.c -L./ -lfoo

-L 은 gcc에게 라이브러리를 찾을 디렉터리를 지정한다.

-l은 링크할 라이브러리를 지정한다. l뒤에 붙은 이름은 라이브러리 이름에서 lib을 뗀(libfoo의 경우 foo만 남는다) 것이며, -l 옵션은 컴파일 할 대상의 소스가 지정되는 뒤에 두면 된다.

 

 

동적 라이브러리 만들기

 

동적 라이브러리를 살펴 볼때도 위에서 나열한 소스를 쓰자. (재활용은 위대하다.)

gcc -fPIC -c foo1.c foo2.c

-fPIC은 컴파일러에게 위치에 상관없이 수행할 수 있는 코드로 컴파일 하라고 하는 것이다. 이제 이렇게 해서 나온 오브젝트 파일을 정적 라이브러리와 합쳐(?)보자.

 

다음과 같이 쳐보자.

gcc -shared -Wl,-soname,libfoo.so.0 -o libfood.so.0.0.0 foo1.o foo2.o

-shared는 동적 라이브러리를 우선 시해서 링크 하라고 지시한다.

-soname은 정적 라이브러리의 soname을 정한다.

 

자 이제 gcc 링크와 동적 링크를 위한 심볼릭 링크만 생성해 주자.

ln -s libfoo.so.0.0.0 libfoo.so
ln -s libfoo.so.0.0.0 libfoo.so.0

libfoo.so는 컴파일 시에 실행 파일들을 링크 할 때 링커가 찾을 수 있게 만든 것이며, libfoo.so.0은 실행 시에 동적 링커가 soname으로 찾을 수 있게 soname을 파일명으로 하는 libfoo.so.0.0.0파일의 심볼릭 링크를 만든 것이다. 

 

동적 링크에 대한 작업도 필요하다.  libfoo.so.0.0.0파일이 있는 디렉터리를 /etc/ld.so.conf에 추가해 줘야 하며, ldconfig로  /etc/ld.so.cache를 새로 생성한다.

 

마지막으로 다음과 같이 실행하여 컴파일 하자.

gcc -o example example.c -L./ -lfoo

 

'프로그래밍 > C' 카테고리의 다른 글

구조체 초기화 방법  (0) 2012.08.21
error: expected identifier before numeric constant  (0) 2012.07.03
sprintf 사용법  (0) 2012.04.03
sscanf 사용법  (0) 2012.03.28
exit(1) vs exit(EXIT_FAILURE)  (0) 2012.02.29
Posted by code cat
프로그래밍/C2012. 4. 3. 20:46

sscanf에 이어 이번에는 sprintf의 사용법에 대해서 알아보자 (sscanf에 대한 사용법은 여기를 참조http://codecat.tistory.com/entry/sscanf-사용법)

 

sprintf는 man page에 다음과 같이 선언되어 있다.

 

int sprintf(char *str, const char *format, ...);


 

sscanf 사용법에서, scanf가 standard input stream, stdin, 에서 input을 읽어오는 반면, sscanf는 str이라는 문자열(character string)에서 입력을 받아온다라고 했는데, sprintf 또한 input<->output이라는 점만 제외하면 이와 유사하다.

 

즉 printf가 standard output stream, stdout에 output을 출력한다면, sprintf는 str이라는 문자열에 출력을 한다고 생각하면 된다.

 

sscanf 사용법에 썼던 예제를 다시 한번 보면, (예제출처: 초보자를 위한 Linux & Unix C 프로그래밍)

sprintf(buff1, "%d", i) 라는 부분이 있다.  이는 위에서 이미 정의된 i를 %d에 맞게 buff1에 출력(저장이라고 보는게 맞겠다)한다고 보면 된다.  (포맷에 관련해서는 sscanf 사용법을 참조하자.)

 

그럼 이걸 언제 써먹냐면은... 물론 여러가지 용도가 있겠지만, 대표적으로 생각나는게 여러가지 옵션을 모아서 하나의 커맨드를 만들어서 실행시킬 때 사용할 수 있겠다. 

 

다음과 같이 실행 커맨드와 옵션들을 긁어 모아서 system()으로 한방에 실행시킬 수 있다.

sprintf(cmd_buf, "%s %s %s", cmd_exec, opt1, opt2);
system(cmd_buf);
Posted by code cat