[c] 정의와 선언의 차이점은 무엇입니까?

둘의 의미는 나를 피한다.



답변

선언 그것을 입력, 개체 또는 함수일, 식별자를 소개하고, 형식을 설명한다. 선언은 컴파일러가 해당 식별자에 대한 참조를 수락 해야하는 것 입니다. 이들은 선언입니다 :

extern int bar;
extern int g(int, int);
double f(int, double); // extern can be omitted for function declarations
class foo; // no extern allowed for type declarations

정의는 실제로 / 구현이 식별자 인스턴스화합니다. 그것은이다 링커 무엇을 필요로하는지 그 실체에 대한 링크를 참조하기 위해. 위의 선언에 해당하는 정의는 다음과 같습니다.

int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};

선언 대신 정의를 사용할 수 있습니다.

식별자는 원하는 횟수 만큼 선언 할 수 있습니다 . 따라서 다음은 C 및 C ++에서 유효합니다.

double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);

그러나 정확히 한 번만 정의 해야합니다 . 선언되고 어딘가에 참조 된 것을 정의하는 것을 잊어 버린 경우 링커는 누락 된 기호에 대한 참조를 링크 할 항목을 모르고 불평합니다. 당신이 한 번 이상 무언가를 정의 할 경우, 링커는 모르고 있는 링크 참조에 대한 정의와 중복 문자 메시지를 뿌려줍니다.


C ++에서 클래스 선언 과 클래스 정의 가 무엇인지에 대한 토론이 계속 나오고 (다른 질문에 대한 답변과 의견으로) C ++ 표준의 인용문을 여기에 붙여 넣을 것입니다.
3.1 / 2에서 C ++ 03은 다음과 같이 말합니다.

선언은 […]가 클래스 이름 선언 […]이 아닌 한 정의입니다.

3.1 / 3은 몇 가지 예를 제공합니다. 그들 중 :

[예: [...]
구조체 S {int a; int b; }; // S, S :: a 및 S :: b를 정의합니다. [...]
구조체 S; // S를 선언
— 끝 예제

이를 요약하면 다음 C ++ 표준은 고려 struct x;선언 하고 정의 . 즉, C ++에는 다른 형식의 클래스 선언이 없으므로 “전달 선언”은 잘못된 이름 입니다.struct x {};

실제 장을 발굴하여 그의 답변 중 하나 를 구사 한 litb (Johannes Schaub) 에게 감사 합니다.


답변

C ++ 표준 섹션 3.1에서 :

선언 이전의 선언에 의해 도입 된 번역 단위 또는 redeclares는 이름으로 소개합니다 이름. 선언은 이러한 이름의 해석 및 속성을 지정합니다.

다음 단락은 (강조 광산) 선언 선언 아니라면

… 함수 본문을 지정하지 않고 함수를 선언합니다.

void sqrt(double);  // declares sqrt

… 클래스 정의 내에서 정적 멤버를 선언합니다.

struct X
{
    int a;         // defines a
    static int b;  // declares b
};

… 클래스 이름을 선언합니다.

class Y;

extern이니셜 라이저 또는 함수 본문이없는 키워드 가 포함되어 있습니다 .

extern const int i = 0;  // defines i
extern int j;  // declares j
extern "C"
{
    void foo();  // declares foo
}

… 또는 typedefor using문입니다.

typedef long LONG_32;  // declares LONG_32
using namespace std;   // declares std

이제 선언과 정의의 차이를 이해하는 것이 중요한 이유는 바로 하나의 정의 규칙 입니다. C ++ 표준의 3.2.1 절에서 :

번역 단위에는 변수, 함수, 클래스 유형, 열거 유형 또는 템플릿에 대한 정의가 둘 이상 포함되어서는 안됩니다.


답변

선언 : “어딘가에 foo가 있습니다.”

정의 : “… 그리고 여기 있습니다!”


답변

C ++에는 흥미로운 경우가 있습니다 (일부는 C에서도). 치다

T t;

어떤 유형인지에 따라 정의 또는 선언이 될 수 있습니다 T.

typedef void T();
T t; // declaration of function "t"

struct X {
  T t; // declaration of function "t".
};

typedef int T;
T t; // definition of object "t".

C ++에서는 템플릿을 사용할 때 또 다른 이점이 있습니다.

template <typename T>
struct X {
  static int member; // declaration
};

template<typename T>
int X<T>::member; // definition

template<>
int X<bool>::member; // declaration!

마지막 선언은 정의 가 아니 었 습니다. 의 정적 멤버를 명시 적으로 전문화 한 선언입니다 X<bool>. 컴파일러에게 “이것이 X<bool>::member인스턴스화하는 경우 기본 템플릿에서 멤버 정의를 인스턴스화하지 말고 다른 곳에서 찾은 정의를 사용하십시오 “라고 알려줍니다 . 그것을 정의로 만들려면 초기화 프로그램을 제공해야합니다

template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.


답변

선언

선언은 컴파일러에게 프로그램 요소 또는 이름이 존재 함을 알려줍니다. 선언은 하나 이상의 이름을 프로그램에 도입합니다. 프로그램에서 선언이 두 번 이상 발생할 수 있습니다. 따라서 클래스, 구조, 열거 유형 및 기타 사용자 정의 유형을 각 컴파일 단위에 대해 선언 할 수 있습니다.

정의

정의는 이름이 설명하는 코드 또는 데이터를 지정합니다. 이름을 사용하려면 먼저 선언해야합니다.


답변

C99 표준에서 6.7 (5) :

선언은 식별자 세트의 해석 및 속성을 지정합니다. 식별자 의 정의 는 다음과 같은 식별자에 대한 선언입니다.

  • 오브젝트의 경우 해당 오브젝트에 대해 스토리지가 예약됩니다.
  • 함수의 경우 함수 본문을 포함합니다.
  • 열거 상수 또는 typedef 이름의 경우 식별자의 유일한 선언입니다.

C ++ 표준 3.1 (2)에서 :

선언은 함수 본문을 지정하지 않고 함수를 선언하지 않는 한 정의 이며 , extern 지정자 또는 연결 지정을 포함하고 초기화 자나 함수 본문을 포함하지 않으며 클래스 선언에서 정적 데이터 멤버를 선언합니다. 클래스 이름 선언이거나 typedef 선언, using-declaration 또는 using-directive입니다.

그런 다음 몇 가지 예가 있습니다.

흥미롭게도 (또는 약간 놀랐습니다) typedef int myint;C99의 정의이지만 C ++의 선언 만입니다.


답변

wiki.answers.com에서 :

선언이라는 용어는 (C에서) 유형, 크기 및 함수 선언의 경우 변수의 매개 변수 유형 및 크기 또는 프로그램에서 사용자 정의 유형 또는 함수에 대해 컴파일러에 알리고 있음을 의미합니다. 선언시 변수를위한 공간이 메모리에 예약되어 있지 않습니다 . 그러나 컴파일러는이 유형의 변수가 생성되는 경우 예약 할 공간을 알고 있습니다.

예를 들어 다음은 모두 선언입니다.

extern int a;
struct _tagExample { int a; int b; };
int myFunc (int a, int b);

반면에 정의는 선언이하는 모든 작업 외에도 공간이 메모리에 예약되어 있음을 의미합니다. “DEFINITION = DECLARATION + SPACE RESERVATION”이라고 정의 할 수 있습니다. 다음은 정의의 예입니다.

int a;
int b = 0;
int myFunc (int a, int b) { return a + b; }
struct _tagExample example; 

답변을 참조하십시오 .