2014-04-20 2 views
3

표준 바이너리가 언제 내 바이너리에 링크되는지 이해하려고합니다. 나는 다음과 같은 쓴 : 그것은 g++ -c main.cpp에 성공적으로 컴파일하는 것표준 C++ 라이브러리 연결

#include <stdio.h> 

double atof(const char*); 

int main(){ 
    const char * v="22"; 
    printf("Cast result is %f", atof(v)); 
} 

을하지만 방금 만든 오브젝트 파일을 링크하고있을 때 나는 오류를했습니다. 오류 설명은 다음과 같습니다.

/tmp/ccWOPOS0.o: In function `main': 
main.cpp:(.text+0x19): undefined reference to `atof(char const*)' 
collect2: error: ld returned 1 exit status 

그러나이 오류의 원인은 무엇입니까? 내 생각에 표준 C++ 라이브러리는 자동으로 내 이진 파일 인 ld 링커에 연결되어 있다고 생각합니다. 헤더 파일을 포함하는 것과 단순히 명시 적으로 사용해야하는 함수를 선언하는 것의 차이점은 무엇입니까?

답변

4

일반적으로 C++에서는 atof()과 같은 라이브러리 함수를 수동으로 선언하는 것은 좋지 않습니다.

이전의 C 프로그램에서는 일반적으로 사용되었지만 C에는 함수 오버로드가 없으므로 "거의"올바른 선언에 대해 더 관대합니다. (예전의 컴파일러 중 일부는 최신의 것을 컴파일 할 수 없다). 그래서 우리는 C를 "약형 언어"로, C++은 좀 더 "강력하게 형식화 된"언어로 설명합니다.

컴파일러가 "이름 맹 글링"을 수행한다는 것은 복잡합니다. 링커에 전달한 이름은 소스 이름의 수정 된 버전입니다. C 컴파일러는 C++ 컴파일러와 완전히 다른 이름 맹 글링을 수행 할 수 있습니다. atof()의 표준 lib 버전은 C 함수입니다.C++ 소스 파일에 선언하려면

extern "C" 
{ 
    double atof(const char *); 
} 

또는 가능

extern "C" double atof(const char *); 

많은 추가적인 복잡성이 있습니다로 선언해야하지만 그와 함께 계속 충분하다.

안전한 아이디어는 적절한 헤더를 포함하는 것입니다.

#include <iostream> 
#include <cstdlib> 

int main() 
{ 
    const char v[]= "22"; 
    std::cout << "Cast result is " << atof(v) << std::endl; 
    return 0; 
} 

응답 추가 배경은 calling convention가에 대한 합의는, 호출 규칙

함수를 호출

  1. @DmitryFucintv로 의견을 어떻게 매개 변수와 값을 반환 호출 함수와 호출 된 함수 사이에서 전달됩니다. x86 아키텍처에서는 가장 일반적인 두 가지가 __cdecl__stdcall이지만 다른 여러 아키텍처도 있습니다.

    는 다음과 같은 고려 : C 프로그램에서

    /* -- f.c --*/ 
    
    int __stdcall f(int a, double b, char *c) 
    { 
        // do stuff 
        return something; 
    } 
    

    /* main.c */ 
    
    #include <iostream> 
    extern int __cdecl f(int a, double b, char *c); 
    
    int main() 
    { 
        std::cout << f(1, 2.3, "45678") << std::endl; 
        return 0; 
    } 
    

    , 이것은 아마 컴파일 및 링크 확인합니다. f() 함수는 args를 __stdcall 형식으로 예상하지만 __cdecl 형식으로 전달합니다. 결과는 불확실하지만 쉽게 스택 손상을 초래할 수 있습니다.

    C++ 링커가 조금 더 까다 롭기 때문에 본 것과 같은 오류가 발생할 것입니다. 대부분이 더 나은 결과라는 데 동의합니다.

    Name Mangling (또는 이름 장식을) 엉망으로

    이 이름은 컴파일러가 링커에 대한 몇 가지 힌트를 제공하기 위해 객체 이름을 몇 가지 추가 문자를 추가하는 방식이다. 오브젝트은 함수 또는 변수 일 수 있습니다. 함수 오버로딩을 허용하는 언어 (C++ 및 Java와 같은)는 링커가 동일한 이름을 가진 여러 함수의 차이점을 알 수 있도록 이와 같은 작업을 수행해야합니다. 예 :

    int f(int a); 
    int f(double a); 
    int f(const char *a, ...); 
    
+1

@PaulR - 물론 정확합니다. 나는 실수를 고쳤다. –

+0

답변 해 주셔서 감사합니다. 하지만 몇 가지 의구심이 있습니다. 순수한 C++ 표준 함수의 경우 추가 수정 자없이 선언 할 수 있습니까? 그리고 저는이 경우 extern "C"를 해결하는 방법에 대해 매우 흥미 롭습니다. –

+0

@DmitryFucintv - 나는 extern "C"가 표준 C++라고 생각한다. 그러나 take-home 메시지는 표준 함수를 직접 선언하는 대신 헤더를 사용하는 것입니다. 왜 직접 함수를 선언하고 싶습니까? 이것에 약간의 유익이 있습니까? –

0

이것은 표준 라이브러리와 아무 관련이 없습니다.

문제는 atof이 정의되지 않아서 링커에서 찾지 못하는 것입니다. 함수를 정의해야합니다. 그렇지 않으면 코드가 무엇을해야하는지 알 수 없습니다.

그리고 atof은 stdlib.h 헤더의 C 함수입니다. 이 코드는 C++ 독점 함수를 사용하지는 않지만 작동해야합니다.

#include <stdlib.h> 

int main(){ 
    const char * v="22"; 
    printf("Cast result is %f", atof(v)); 
} 
1

atof는 C 결합을 가지고 있기 때문에, 그리고 당신은 C++로 이것을 컴파일하고 - 변경 :

double atof(const char*); 

에 :

extern "C" double atof(const char*); 

그것은 작동합니다.

은 분명히 당신은 일반적으로이 작업을 수행해서는 안하고 그냥 올바른 헤더를 사용해야합니다 : 당신이 atof 선언 할 때, 당신은 표준 하나에 미묘하게 다른 기능을 선언하고

#include <cstdlib> 
0

합니다. 선언중인 함수는 이 아니며이 표준 라이브러리에 정의되어 있습니다.

표준 함수를 잘못 선언하는 경우가 있기 때문에 표준 함수를 다시 선언하지 마십시오. 당신은 헤더를 포함하고 헤더는 당신을 위해 함수를 올바르게 선언합니다.

관련 문제