왜 C에서 수학 라이브러리를 연결해야합니까?


254

C 프로그램을 포함 <stdlib.h>하거나 <stdio.h>C 프로그램에 포함시킬 경우 컴파일 할 때 이들을 링크 할 필요는 없지만 gcc를 <math.h>사용하여 에 링크해야 -lm합니다 (예 :

gcc test.c -o test -lm

그 이유는 무엇입니까? 수학 라이브러리를 명시 적으로 링크해야하지만 다른 라이브러리는 아닌 이유는 무엇입니까?

답변:


249

의 기능 stdlib.hstdio.h의 구현이 libc.so(또는 libc.a정적 링크에 대한) (것처럼 기본적으로 실행으로 연결되어, -lc지정된)를. GCC는 -nostdlib또는 -nodefaultlibs옵션 과의이 자동 링크를 피하도록 지시 할 수 있습니다.

수학 함수의 math.h구현은 libm.so(또는 libm.a정적 연결) libm기본적으로 연결되어 있지 않습니다. 이 libm/ libc분할에 대한 역사적인 이유가 있지만 그중 어느 것도 설득력이 없습니다.

흥미롭게도 C ++ 런타임 libstdc++에는을 필요 libm로하므로 GCC ( g++) 로 C ++ 프로그램을 컴파일 하면 자동으로 libm연결됩니다.


8
Linux와는 거리가 멀기 때문에 Linux와는 아무런 관련이 없습니다. 수학 함수를 필요로하지 않는 많은 프로그램이 있기 때문에 실행 파일 크기를 최소화하려고 시도하는 것과 관련이 있다고 생각합니다.
David Thornley 2016 년

39
고대 시스템에서 수학 함수가 libc에 포함 된 경우 모든 프로그램을 컴파일하면 속도가 느리고 출력 실행 파일이 커지며 런타임에는 더 많은 메모리가 필요하며 이러한 수학 함수를 전혀 사용하지 않는 대부분의 프로그램 에는 이점 이 없습니다. 요즘 우리는 공유 라이브러리를 잘 지원하고 있으며 정적으로 링크 할 때도 사용하지 않는 코드를 버릴 수 있도록 표준 라이브러리가 설정되어 있으므로 더 이상 좋은 이유는 없습니다.
ephemient 2016 년

38
@ephemient 옛날에도 라이브러리에 링크해도 라이브러리의 모든 내용을 실행 파일로 가져 오지 못했습니다. 링커는 종종 무시되는 기술이지만 역사적으로 매우 효율적입니다.

7
@ephemient 또한, 공유 라이브러리는 생각보다 오래 지속되었습니다. 그것들은 1980 년대가 아니라 1950 년대에 발명되었습니다.

5
나는 우리가보고있는 것은 GCC 보수주의에 지나지 않는다고 생각한다. "항상 그렇게 작동했다". 컴파일러 확장에 동일한 추론을 적용하기를 바랍니다.

77

C는 오래된 언어이며 FPU는 비교적 최근의 현상이라는 것을 기억하십시오. 나는 8 비트 프로세서에서 C를 처음 보았는데 32 비트 정수 산술조차도 많은 작업이었습니다. 이러한 구현 중 다수 에는 부동 소수점 수학 라이브러리 도 없었 습니다!

최초의 68000 시스템 (Mac, Atari ST, Amiga)에서도 부동 소수점 코 프로세서는 종종 고가의 애드온이었습니다.

모든 부동 소수점 수학을 수행하려면 꽤 큰 라이브러리가 필요했습니다. 그리고 수학은 느려질 것입니다. 따라서 거의 플로트를 사용하지 않았습니다. 정수 또는 스케일 정수로 모든 것을하려고했습니다. math.h를 포함시켜야했을 때 이빨을 gri습니다. 종종, 당신은 그것을 피하기 위해 자신의 근사치와 룩업 테이블을 작성할 것입니다.

트레이드 오프는 오랫동안 존재했습니다. 때로는 "fastmath"등의 경쟁 수학 패키지가있었습니다. 수학에 가장 적합한 솔루션은 무엇입니까? 정말 정확하지만 느린 것? 부정확하지만 빠르다? 삼각 함수를위한 큰 테이블? 코 프로세서가 컴퓨터에 내장되어 있어야 대부분의 구현이 명백해졌습니다. 나는 어딘가에 프로그래머가 임베디드 칩에서 작업하면서 수학 문제를 처리하기 위해 수학 라이브러리를 가져올 지 결정하려고한다고 생각합니다.

이것이 수학이 표준 이 아닌 이유 입니다. 대부분 또는 대부분의 프로그램은 단일 부동 소수점을 사용하지 않았습니다. FPU가 항상 주변에 있었고 플로트 및 복식이 항상 작동하기에 저렴하다면 "stdmath"가 있었을 것입니다.


그는 데스크톱 PC에서 Java의 (1 + x) ^ y에 대해 Pade 근사값을 사용하고 있습니다. 로그, exp 및 pow는 여전히 느립니다.
quant_dev 2016 년

좋은 지적. 그리고 오디오 플러그인에서 sin ()에 대한 근사치를 보았습니다.
Nosredna 2016 년

11
이유를 설명 libm기본적으로 연결되지 않지만, 수학이었다 표준 C89에서 그 전에, K & R이 있었다 사실상이 당신의 "stdmath"발언이 이해가되지 않습니다, 그래서 그것을 표준화.
프레드 푸

@FredFoo 유형과 인터페이스는 표준화되었지만 구현은 아닙니다. 나는 Nosredna가 표준 수학 라이브러리를 참조하고 있다고 생각합니다.
팀 버드

72

아무도 고칠 수없는 어리석은 역사적 관행 때문에. C 및 POSIX에 필요한 모든 기능을 단일 라이브러리 파일로 통합하면이 질문이 계속 반복되는 것을 피할 수있을뿐만 아니라 .so링크 된 각 파일에 파일 시스템 조작이 필요 하므로 동적 링크시 상당한 시간과 메모리를 절약 할 수 있습니다. 정적 변수, 재배치 등에 대한 몇 페이지를 찾아서 찾을 수 있습니다.

모든 기능을 하나의 라이브러리와에 구현 -lm, -lpthread, -lrt, 등의 옵션이 전혀 작전 (또는 빈 링크없는 .a파일) 완벽하게되어 POSIX의 준수와 확실히 바람직하다.

참고 : C 자체는 컴파일러 호출 방법에 대해 아무것도 지정하지 않기 때문에 POSIX에 대해 이야기하고 있습니다. 따라서 gcc -std=c99 -lm적합한 동작을 위해 컴파일러를 호출해야하는 구현 별 방식으로 취급 할 수 있습니다 .


9
POSIX는 분리 된 libm, libc 및 librt 라이브러리가 필요하지 않음을 +1합니다. 예를 들어, Mac OS에서는 모든 것이 단일 libSystem (libdbm, libdl, libgcc_s, libinfo, libm, libpoll, libproc 및 librpcsvc도 포함)에 있습니다.
F'x

3
–1 링크 또는 숫자로 백업하지 않고 라이브러리 조회가 성능에 미치는 영향을 추측합니다. "프로필. 추측하지 마십시오"
F'x

12
이것은 추측이 아닙니다. 게시 된 논문이 없지만 모든 측정을 직접 수행했는데 그 차이가 큽니다. strace타이밍 옵션 중 하나와 함께 사용 하여 동적 링크에 소요되는 시작 시간을 확인하거나 ./configure모든 표준 유틸리티가 정적 링크 된 시스템 과 동적 링크 된 시스템에서 실행 하는 것을 비교 하십시오. 주류 데스크톱 앱 개발자 및 시스템 통합 자조차도 동적 연결 비용을 알고 있습니다. 이것이 프리 링크와 같은 것들이 존재하는 이유입니다. 이 논문들 중 일부에서 벤치 마크를 찾을 수 있다고 확신합니다.
R .. GitHub 중지 지원 얼음

1
POSIX는 것을 참고 않는 요구는 -lm받아 들여 사용해야 수학 인터페이스를 사용하는 응용 프로그램 수 -lm있지만, 내부 옵션은 컴파일러 명령이 아닌 실제 라이브러리 파일에 의해 처리 (또는 무시) 할 수 있습니다. 또는 .a인터페이스가 기본 libc에있는 경우 빈 파일 일 수 있습니다 .
R .. GitHub 중지 지원 얼음

6
@FX : 내가 왜 이것을 언급하지 않았는지 모르겠다 : strace -tt동적 연결에 소요 된 시간을 쉽게 보여줄 것이다. 예쁘지 않아요. 그리고 Linux에서 검사 /proc/sys/smaps하면 추가 라이브러리의 메모리 오버 헤드가 표시됩니다.
R .. GitHub 중지 지원 얼음

33

때문에 time()일부 다른 기능이 있습니다 builtin(C 라이브러리에 정의 libc자체) 및 GCC는 항상 libc에 대한 링크 하지 않는 한 당신이 사용하는 -ffreestanding컴파일 옵션을 선택합니다. 그러나 수학 함수 libm는 gcc에 의해 암시 적으로 연결되어 있지 않습니다.


8
LLVM gcc에서는 -lm을 추가 할 필요가 없습니다. 왜 이런거야?
bot47

26

여기에 설명이 있습니다 :

따라서 프로그램에서 수학 함수를 사용하고를 포함 math.h하는 경우 -lm플래그 를 전달하여 수학 라이브러리를 명시 적으로 연결해야합니다 . 이 분리의 이유는 수학자들이 수학 계산 방식에 매우 까다롭기 때문에 표준 구현 대신 수학 함수의 자체 구현을 사용하고자 할 수 있기 때문입니다. 수학 함수가 집중되어 libc.a있다면 그렇게 할 수 없습니다.

[편집하다]

그래도 동의하지는 않습니다. 예를 들어을 제공하는 라이브러리가 sqrt()있고 표준 라이브러리보다 먼저 전달하면 Unix 링커가 버전을 가져옵니다.


10
나는 그것이 일어날 것이라는 보장이 없다고 생각합니다. 대신 기호 충돌이 발생할 수 있습니다. 링커와 라이브러리의 레이아웃에 따라 다릅니다. 나는 여전히 그 이유가 약하다는 것을 안다. 만약 당신이 커스텀 sqrt 함수를 만들고 있다면, 같은 기능을하더라도 표준 sqrt 함수와 같은 이름을 지정해서는 안됩니다.
ephemient

1
실제로, 자신의 함수 (비 정적)로 이름을 지정 sqrt하면 정의되지 않은 동작의 프로그램이 생성됩니다.
R .. GitHub 중지 지원 얼음

@Bastien 잘 찾았습니다. 그리고 당신의 요점에 오면, "표준 라이브러리 이전"이란 무엇을 의미합니까? 표준 라이브러리는 기본적으로 연결되어 있으며 명령 줄 옵션을 통해 연결하지 않아도된다고 생각했습니다. 따라서 표준 라이브러리는 링커의 첫 번째 방법이며 "표준 라이브러리 앞에"자체 구현을 배치 할 수 없습니다.
Rocky Inde

@RockyInde : 내 대답을 봐, 나는 실제로“표준 수학 라이브러리 이전”을 의미한다고 생각합니다. 그러나 표준 C 라이브러리를 링크하지 않는 컴파일러 옵션이 있다고 생각합니다.
Bastien Léonard

@ BastienLéonard 나는 -lm완전히 선택적 인 7.2 버전의 gcc를 사용 합니다. 어떤 아이디어
Donghua Liu

5

GCC 소개- 외부 라이브러리와 링크에서 외부 라이브러리에 대한 링크에 대해 자세히 설명 합니다. 라이브러리가 표준 라이브러리 (stdio와 같은)의 멤버 인 경우, 라이브러리를 링크하기 위해 컴파일러 (실제로 링커)를 지정할 필요가 없습니다.

편집 : 다른 답변과 의견 중 일부를 읽은 후 libc.a 참조 와 libm 참조가 둘 다 연결되는 이유에 대해 말할 것이 많이 있다고 생각합니다.

'libm.a'(수학 라이브러리)의 많은 함수는 'math.h'에 정의되어 있지만 libc.a에는 없습니다. 일부는 혼란 스러울 수 있지만 일반적으로 C 라이브러리에는 ANSI 지시문이 있어야하는 함수가 있으므로 ANSI 함수 만 사용하는 경우 -lm이 필요하지 않습니다. 반면에 'libm.a'는 더 많은 기능을 포함하고 있으며 matherr 콜백 및 FP 오류 발생시 몇 가지 대체 행동 표준 준수와 같은 추가 기능을 지원합니다. 자세한 내용은 libm 섹션을 참조하십시오.


1
왜 일치 라이브러리에서 별도로 링크해야하는지에 대한 질문에 대답하지 않습니다. 분명히 OpenGL 라이브러리를 별도로 연결해야하지만 수학 라이브러리가 일반적으로 유용합니다.
David Thornley 2016 년

@David : 맞습니다. 이것이 OP가 요구 한 비트라는 질문에서 분명하지 않았습니다. 당신이 코멘트 한대로 내 대답을 편집하고있었습니다.
Bill the Lizard

sqrt함수 를 사용하는 프로그램을 컴파일 한 이유를 알고 있으며 를 통해 라이브러리를 포함하지 않고 작동합니다 -lm. 감사!
L_K

5

ephemient가 말했듯이 C 라이브러리 libc는 기본적으로 링크되어 있으며이 라이브러리에는 stdlib.h, stdio.h 및 기타 여러 표준 헤더 파일의 구현이 포함되어 있습니다. " GCC 소개 "에 따르면 C에 기본 "Hello World"프로그램에 대한 링커 명령은 다음과 같습니다.

ld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o 
/usr/lib/crti.o /usr/libgcc-lib /i686/3.3.1/crtbegin.o
-L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh -lc 
-lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o /usr/lib/crtn.o

C 라이브러리를 링크하는 세 번째 행에서 -lc 옵션 을 확인하십시오.


3

나는 그것이 임의의 것이라고 생각합니다. 어딘가에 선을 그려야합니다 (어떤 라이브러리가 기본이고 어떤 라이브러리가 지정되어야하는지).

그것은 당신에게 같은 기능을 가진 다른 것으로 교체 할 수있는 기회를 제공하지만, 그렇게하는 것이 일반적이라고 생각하지 않습니다.

편집 : (내 의견에서) : gcc는 원본 cc와의 하위 호환성을 유지하기 위해이 작업을 수행한다고 생각합니다. cc가 왜 이런 일을하는지에 대한 추측은 빌드 시간 때문입니다. cc는 지금보다 훨씬 적은 전력을 사용하는 기계 용으로 작성되었습니다. 많은 프로그램에는 부동 소수점 수학이 없으며 일반적으로 기본값에서 사용되지 않는 모든 라이브러리를 사용했을 것입니다. UNIX OS의 빌드 시간과 함께 제공되는 도구가 원동력이라고 생각합니다.


나는 질문의 배후에 libm의 내용이 표준 C 라이브러리의 일부라고 생각합니다. 왜 libc에 있지 않습니까?
Evan Teran 2016 년

1
gcc의 이유는 AT & T Unix에서 원본 cc와의 호환성을 유지하는 것입니다. 1988 년에 3B2를 사용했고 수학을 구하려면 -lm을 사용해야했습니다. 당시에는 완전히 임의적 인 것처럼 보였습니다. Visual Studio에서는 수학을 추가해야한다는 것을 기억하지 못하지만 때로는 다른 c 런타임 라이브러리를 추가해야합니다. 컴파일러 공급 업체에 이유 (빌드 시간?)가 있다고 가정하지만 지금은 gcc가 이전 버전과 호환되도록 노력하고 있다고 확신합니다.
Lou Franco

3

stdlib.h 또는 stdio.h를 넣으면 링크 할 필요는 없지만 컴파일 할 때 링크해야합니다.

stdlib.h, stdio.h헤더 파일입니다. 당신은 당신의 편의를 위해 그들을 포함합니다. 적절한 라이브러리에 연결하면 사용할 수있는 기호 만 예측합니다. 구현은 라이브러리 파일에 있으며, 그 기능이 실제로 존재합니다.

포함 math.h은 모든 수학 기능에 액세스하는 첫 번째 단계 일뿐입니다.

또한 libm함수를 사용하지 않으면 링크에 대해 링크 할 필요가 없습니다. 심지어 #include <math.h>컴파일러에 대해 정보 단계 일뿐입니다.

stdlib.h에서 stdio.h사용할 수있는 기능을 참조하십시오.이 기능 libc은 사용자가 직접 할 필요가 없도록 항상 연결되어 있습니다.


2

stdio는 기본적으로 gcc가 연결할 표준 C 라이브러리의 일부입니다.

수학 함수 구현은 기본적으로 연결되어 있지 않은 별도의 libm 파일에 있으므로 -lm을 지정해야합니다. 그건 그렇고, 헤더 파일과 라이브러리 파일 사이에는 아무런 관계가 없습니다.


3
그는 알고 있습니다 .. 그는
Evan Teran

그는 이유를 말합니다. Simon은 stdio와 같이 일부 라이브러리는 기본적으로 연결되어 있지만 수학 라이브러리는 기본적으로 연결되어 있지 않으므로 지정해야한다고 설명합니다.
mnuzzo 2016 년

5
나는 질문의 본질이 왜 libm이 기본적으로 링크되어 있지 않은지 (또는 libc와 분리되지 않은) 왜 그 내용이 c 표준 라이브러리의 일부이기 때문에 묻는 것입니다.
Evan Teran 2016 년

2

전혀 사용하지 않는 앱을 ​​약간 더 잘 수행하는 방법 이라고 생각 합니다. 여기에 내 생각이 있습니다.

x86 OS (그리고 다른 사람들도)는 FPU 상태를 컨텍스트 스위치에 저장해야합니다. 그러나 대부분의 OS는 앱이 처음으로 FPU를 사용하려고 시도한 후에 만이 상태를 저장 / 복원하려고합니다.

이 외에도 수학 라이브러리에는 라이브러리가로드 될 때 FPU를 정상적인 기본 상태로 설정하는 기본 코드가있을 수 있습니다.

따라서 수학 코드를 전혀 링크하지 않으면이 중 어느 것도 발생하지 않으므로 OS는 FPU 상태를 전혀 저장 / 복원 할 필요가 없으므로 컨텍스트 전환이 약간 더 효율적입니다.

그래도 추측.

편집 : 일부 의견에 대한 응답으로 동일한 기본 전제는 여전히 FPU가 아닌 경우에 적용됩니다 (전제는 libm을 사용하지 않는 앱을 ​​약간 더 잘 수행해야한다는 전제입니다).

예를 들어, C의 초기에 likley 인 soft-FPU가있는 경우 libm을 분리하면 많은 (그리고 사용 된 경우 느린) 코드가 불필요하게 연결되는 것을 막을 수 있습니다.

또한 정적 링크 만 사용할 수있는 경우 실행 가능한 크기와 컴파일 시간이 줄어드는 유사한 인수가 적용됩니다.


libm과 연결하지 않고 다른 방법 (예 : 플로트 작업)을 통해 x87 FPU를 터치하면 x86 커널은 FPU 상태를 저장해야합니다. 나는 이것이 아주 좋은 추측이라고 생각하지 않습니다 ...
ephemient

물론 수동으로 FPU를 사용하면 커널은 여전히 ​​상태를 저장 / 복원해야합니다. 나는 당신이 그것을 사용하지 않으면 (libm을 사용하지 않는 것을 포함하여) 그렇게 할 필요가 없다고 말하고있었습니다.
Evan Teran 2016 년

실제로 커널에 크게 의존 할 수 있습니다. 커널이 사용하는 수학 라이브러리에는이를 켜는 save_FPU_on_switch () 함수가있을 수 있지만 다른 라이브러리는 FPU가 터치되었는지 여부 만 감지합니다.
Earlz 2016 년

1
올바르게 기억한다면 전체 문제는 부동 소수점 코 프로세서가 마이크로 프로세서에있는 경우에도 오래 지속됩니다.
Nosredna 2016 년

@earlz : 수학 라이브러리 요청 저장 방식은 끔찍한 디자인입니다. 다른 방법으로 FPU를 사용하면 어떻게됩니까? (항상 저장 / 복원 이외의) 유일한 방법은 사용량을 감지 한 다음 저장 / 복원을 시작하는 것입니다.
Evan Teran 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.