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


857

둘의 의미는 나를 피한다.


91
@Lasse : 사실이 아닙니다. 정의는 ;-)를 정의하고 선언합니다
Steve Jessop

13
솔직히, 나는 많은 학습에 어려움을 겪었으므로 이름이 분명하지 않았습니다. 나는 의미에 아무런 문제가 없었으며, 그 의미와 연관시킬 이름이 있습니다.
David Thornley

6
여전히 C / C ++에 대해 묻는 반면 다른 질문은 일반적으로 모든 언어에 대해 또는 전혀없는 질문이므로 중복 질문은 아닙니다. 중복 답변이 있습니다 (다른 질문 때문에 일부 답변은 C 및 / 또는 C ++을 제외한 모든 언어를 무시하기로 선택했습니다).
Steve Jessop

5
나는이 트릭을 사용 @DavidThornley하십시오 정의는 제공 미세한 주어진 변수 나 함수의 설명. 이것을 기억하기 위해, "정의"라는 단어의 중간에는 "finer"라는 단어가 있습니다. :)
Marco Leogrande

4
이 질문에 얼마나 많은 쓰레기가 있는지 놀랍습니다. 이 언어가 얼마나 많이 오해 되는지 , 그리고 그 오해가 일상적으로 어떻게 전파 되는지를 보여 주기만하면 됩니다. 정말 슬프다.
궤도에서 가벼움 경주

답변:


858

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

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) 에게 감사 합니다.


2
@unknown : 컴파일러가 잘못 복사되어 sbi의 코드가 잘못되었습니다. 예를 들어 N1124의 6.7.2 (2) : "동일한 객체 또는 함수를 참조하는 모든 선언은 호환되는 유형을 가져야합니다. 그렇지 않으면 동작이 정의되지 않습니다."
Steve Jessop

4
@ 브라이언 : "extern int i;" 내가 어딘가에 있다고 걱정하지 마십시오. "int i;" i는 int이며 해당 주소와 범위는 여기에서 결정됩니다.
David Thornley

12
@ 브라이언 : 당신이 틀렸다. extern int i그냥 소개 / 지정하기 때문에 선언 i입니다. extern int i각 컴파일 단위에 원하는만큼을 가질 수 있습니다 . int i그러나 정의입니다. 정수가이 변환 단위에있는 공간을 나타내며 링커가 모든 i엔티티를이 엔티티에 링크하도록 조언합니다 . 이러한 정의 중 하나 이상을 가지고있는 경우 링커가 불평합니다.
sbi

4
int i;파일 / 글로벌 범위 또는 함수 범위의 @Brian 은 C 및 C ++ 모두에서 정의됩니다. C에서는 스토리지를 할당하기 때문에 C ++에서는 extern 지정자 또는 링크 지정이 없으므로 C ++에서. 이것들은 sbi가 말하는 것과 같은 것입니다. 두 경우 모두이 선언은 해당 범위에서 "i"에 대한 모든 참조가 연결되어야하는 객체를 지정합니다.
Steve Jessop

4
@unknown, 클래스 범위 에서 멤버를 다시 선언 할 수는 없습니다 struct A { double f(int, double); double f(int, double); };. 물론 유효하지 않습니다. 그래도 다른 곳에서는 허용됩니다. 선언 할 수는 있지만 정의 할 수없는 곳도 있습니다. void f() { void g(); }유효하지만 다음은 아닙니다 void f() { void g() { } };.. 템플릿이란 무엇인가? 정의 란 무엇이며 선언에는 미묘한 규칙이 있습니다. 좋은 답변은 +1입니다.
Johannes Schaub-litb

168

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 절에서 :

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


"클래스 정의 내에 정적 멤버를 선언합니다"-정적 멤버가 초기화 된 경우에도 마찬가지입니다. 맞습니까? 예를 들어 볼까요 struct x {static int b = 3; };?
RJFalconer

@RJFalconer 당신이 맞습니다; 초기화가 선언을 정의로 바꿔야 할 필요 는 없습니다 (예상 한 것과는 반대로, 확실히이 놀라운 것을 발견했습니다). b또한 선언 하지 않는 한 예제에 대한 수정은 실제로 불법 const입니다. stackoverflow.com/a/3536513/1858225daniweb.com/software-development/cpp/threads/140739/…를 참조하십시오 .
Kyle Strand

1
이것은 나에게 흥미 롭다. 귀하의 답변에 따르면 C ++에서는 선언 정의 (예외 포함) 인 반면, C 표준에서는 다른 관점 (C99, 섹션 6.7, 선언)에서 표현됩니다. " 식별자 의 정의 는 다음과 같습니다. 해당 식별자에 대한 선언 : [다른 사례에 대한 기준]]. 다른 방법으로 볼 수 있다고 생각합니다. :)
Victor Zamanian

선언은 컴파일러가 이름을 받아들이는 것입니다 (컴파일러에게 이름이 합법적임을 알리기 위해 오타가 아닌 의도로 이름이 도입 됨). 정의는 이름과 내용이 연관되는 곳입니다. 링커는이 정의를 사용하여 이름 참조를 이름의 컨텐츠에 링크합니다.
Gab 是 好人

137

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

정의 : "... 그리고 여기 있습니다!"


3
선언은 컴파일러가 이름을 받아들이는 것입니다 (컴파일러에게 이름이 합법적임을 알리기 위해 오타가 아닌 의도로 이름이 도입 됨). 정의는 이름과 내용이 연관되는 곳입니다. 링커는이 정의를 사용하여 이름 참조를 이름의 컨텐츠에 링크합니다.
Gab 是 好人

46

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.

35

선언

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

정의

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


음, 각 컴파일 단위에서 클래스와 열거 형을 정의 할 수도 있습니까? 적어도 클래스 정의 를 헤더에 넣고 모든 것을 포함시킵니다. 어, class foo {}; 클래스 정의는 , 그렇지?
sbi

1
예. 그러나 "class foo;" 선언입니다. 컴파일러에게 foo가 클래스임을 알려줍니다. "class foo {};" 정의입니다. 컴파일러에게 클래스 foo의 종류를 정확하게 알려줍니다.
David Thornley

1
예외는 선언되기 전에 사용될 수있는 클래스 멤버 이름입니다.
Johannes Schaub-litb

1
그래, 그게 내 뜻이야 따라서 다음을 수행 할 수 있습니다. struct foo {void b () {f (); } void f (); }, f는 아직 선언되지 않았더라도 볼 수 있습니다. 다음도 작동합니다. struct foo {void b (int = bar ()); typedef int 바; } ;. "모든 함수 본문, 기본 인수, 생성자 ctor-initializers"에서 선언하기 전에 볼 수 있습니다. 반환 유형이 아님 :(
Johannes Schaub-litb

1
@litb : 선언하기 전에 표시되지 않습니다 . 식별자 사용 은 선언 뒤로 만 이동됩니다. 예, 많은 경우에 그 효과는 동일합니다. 그러나 모든 경우에 해당되는 것은 아니므로 정확한 설명을 사용해야한다고 생각합니다. -기다려 기본 인수로 볼 수 있습니까? 글쎄, 그것은 분명히 내 이해에 혼란을 초래합니다. 젠장! <pouts>
sbi

22

C99 표준에서 6.7 (5) :

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

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

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

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

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

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


@onebyone :와 관련하여 typedefC99에서는 반복 할 수는 있지만 C99에서는 반복 될 수 없다는 것을 의미하지 않습니까?
sbi

그것은 저를 놀라게했으며 단일 번역 단위에 관한 한 그 차이가 있습니다. 그러나 분명히 C99에서는 다른 번역 단위로 typedef를 반복 할 수 있습니다. C에는 C ++과 같은 명시적인 "하나의 정의 규칙"이 없으므로 허용되는 규칙 만 있습니다. C ++은 선언으로 변경하기로 결정했지만 하나의 정의 규칙에 적용되는 종류가 나열되어 있으며 typedef는 그중 하나가 아닙니다. 따라서 typedef가 정의 인 경우에도 ODR에서 C ++에서 반복이 허용됩니다. 불필요하게 까다로운 것 같습니다.
Steve Jessop

...하지만 ODR의 해당 목록에는 실제로 정의 할 수있는 모든 항목이 나열되어 있습니다. 그렇다면 목록은 실제로 중복되며 도움이 될 것입니다.
Steve Jessop

std의 ODR 정의는 클래스 정의에 대해 무엇을 말합니까? 그들은 반복 될 수 있습니다.
sbi

2
@sbi : ODR에 따르면 "(1) 번역 ​​단위에는 클래스 유형에 대한 정의가 두 개 이상 포함되어서는 안됩니다."및 "(5) 클래스 유형에 대한 정의가 둘 이상있을 수 있습니다 ... 각 정의는 다른 번역 단위로 표시되고 "정의가 동일한"추가 요구 사항이 있습니다.
Steve Jessop

17

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; 

답변을 참조하십시오 .


3
이것도 잘못된 것입니다 (다른 것보다 훨씬 가깝지만) : 선언 struct foo {};이 아니라 정의 입니다. 의 선언은 foo입니다 struct foo;. 그로부터 컴파일러는 foo객체 를 예약 할 공간이 얼마나되는지 알지 못합니다 .
sbi

1
@Marcin : sbi는 "컴파일러는이 유형의 변수가 생성 될 때 예약 할 공간을 알고 있습니다"라고 항상 말하는 것은 아닙니다. struct foo;선언이지만 컴파일러에게 foo의 크기를 알려주지는 않습니다. 나는 그것을 struct _tagExample { int a; int b; };정의라고 덧붙였다. 따라서 이러한 맥락에서 선언이라고 부르는 것은 잘못된 것입니다. 물론 모든 정의가 선언이기 때문에 하나이지만 정의가 아니라고 제안하는 것 같습니다. _tagExample의 정의입니다.
Steve Jessop

1
@Marcin Gil : "Answers"위키가 항상 정확한 것은 아닙니다. 나는 잘못된 정보를 위해 여기에 투표해야한다.
David Thornley

1
우리는 인용 된 데이터가 사실이지만 실제로 (IMO) 질문에 대답하지 않는다는 것을 배웁니다. Marcin이 인용 한 것은 거짓입니다. 표준을 인용하는 것은 사실이며 질문에 대답하지만, 머리 나 꼬리를 만들기가 매우 어렵습니다.
Steve Jessop

1
@David Thornley-문제가 아닙니다 :) 이것이이 사이트에 관한 것입니다. 우리는 선택하고 정보를 확인합니다.
Marcin Gil

13

C ++ 11 업데이트

C ++ 11과 관련된 대답을 볼 수 없으므로 여기에 하나가 있습니다.

선언은 a / n을 선언하지 않는 한 정의입니다 .

  • 불투명 열거 형- enum X : int;
  • 템플릿 매개 변수 -T intemplate<typename T> class MyArray;
  • 매개 변수 선언 - XYint add(int x, int y);
  • 별칭 선언- using IntVector = std::vector<int>;
  • 정적 주장 선언- static_assert(sizeof(int) == 4, "Yikes!")
  • 속성 선언 (구현 정의)
  • 빈 선언 ;

위의 목록에 의해 C ++ 03에서 상속 된 추가 절 :

  • 함수 선언 - 추가int add(int x, int y);
  • 선언 또는 링크 지정자를 포함하는 extern 지정자- extern int a;또는extern "C" { ... };
  • 클래스의 정적 데이터 멤버 -x inclass C { static int x; };
  • 클래스 / 구조 선언- struct Point;
  • typedef 선언- typedef int Int;
  • 선언을 사용하여- using std::cout;
  • 지시문 사용- using namespace NS;

템플릿 선언은 선언입니다. 템플릿 선언은 선언이 함수, 클래스 또는 정적 데이터 멤버를 정의하는 경우의 정의이기도합니다.

선언과 정의 사이의 뉘앙스를 이해하는 데 도움이되는 표준의 예 :

// except one all these are definitions
int a;                                  // defines a
extern const int c = 1;                 // defines c
int f(int x) { return x + a; }          // defines f and defines x
struct S { int a; int b; };             // defines S, S::a, and S::b
struct X {                              // defines X
    int x;                              // defines non-static data member x
    static int y;                       // DECLARES static data member y
    X(): x(0) { }                       // defines a constructor of X
};
int X::y = 1;                           // defines X::y
enum { up , down };                     // defines up and down
namespace N { int d; }                  // defines N and N::d
namespace N1 = N;                       // defines N1
X anX;                                  // defines anX


// all these are declarations
extern int a;                           // declares a
extern const int c;                     // declares c
int f(int);                             // declares f
struct S;                               // declares S
typedef int Int;                        // declares Int
extern X anotherX;                      // declares anotherX
using N::d;                             // declares N::d


// specific to C++11 - these are not from the standard
enum X : int;                           // declares X with int as the underlying type
using IntVector = std::vector<int>;     // declares IntVector as an alias to std::vector<int>
static_assert(X::y == 1, "Oops!");      // declares a static_assert which can render the program ill-formed or have no effect like an empty declaration, depending on the result of expr
template <class T> class C;             // declares template class C
;                                       // declares nothing

6

정의 :

extern int a;      // Declaration 
int a;             // Definition
a = 10             // Initialization
int b = 10;        // Definition & Initialization

정의는 변수를 형식과 연결하고 메모리를 할당하지만 선언은 형식을 지정하지만 메모리를 할당하지는 않습니다. 선언은 정의하기 전에 변수를 참조 할 때 더 유용합니다.

* 정의와 초기화를 혼동하지 마십시오. 둘 다 다르며 초기화는 변수에 가치를 부여합니다. 위의 예를 참조하십시오.

다음은 정의의 몇 가지 예입니다.

int a;
float b;
double c;

이제 함수 선언 :

int fun(int a,int b); 

함수 끝의 세미콜론은 선언 일뿐입니다. 컴파일러는 프로그램의 해당 위치 가 해당 프로토 타입 으로 정의 될 것임을 알고 있습니다 . 컴파일러가 다음과 같은 함수 호출을 얻는다면

int b=fun(x,y,z);

컴파일러는 그러한 기능이 없다는 오류를 발생시킵니다. 해당 기능에 대한 프로토 타입이 없기 때문입니다.

두 프로그램의 차이점에 유의하십시오.

프로그램 1

#include <stdio.h>
void print(int a)
{
     printf("%d",a);
}
main()
{
    print(5);
}

여기에서 인쇄 함수도 선언 및 정의됩니다. 함수 호출은 정의 뒤에옵니다. 이제 다음 프로그램을보십시오.

프로그램 2

 #include <stdio.h>
 void print(int a); // In this case this is essential
 main()
 {
    print(5);
 }
 void print(int a)
 {
     printf("%d",a);
 }

함수 호출이 정의보다 우선하므로 컴파일러는 그러한 함수가 있는지 알아야합니다. 따라서 컴파일러에게 알려주는 함수를 선언합니다.

정의 :

함수를 정의하는이 부분을 정의라고합니다. 함수 안에서 무엇을해야하는지 알려줍니다.

void print(int a)
{
    printf("%d",a);
}

2
int a; //declaration; a=10; //definition이것은 완전히 잘못되었습니다. 자동 스토리지 기간 오브젝트 (extern과 같은 다른 스토리지 클래스 지정자로 선언되지 않은 함수 정의 내에서 선언 된 오브젝트)에 대해 이야기 할 때는 항상 정의입니다.
Joey Pabalinas

파악해야 할 가장 큰 차이점은 선언은 "이러한 특성 (유형 등)이있는 곳에 존재하는 것"이라고 말하고 정의는 "이러한 특성이있는 것을 선언하고 있으며 여기에서이를 인스턴스화하는 것"이라는 것입니다. 잘." 이와 같은 자동 저장 기간 개체를 전달할 수 없으므로 항상 정의가됩니다.
Joey Pabalinas

내가 항상 잊어 버린 이상한 typedef 코너 경우를 제외하고는 일반적으로 모든 정의는 선언이라는 것입니다. 생각해보십시오. 무언가를 인스턴스화 할 때 컴파일러에게 그 것이 존재하고 그 특성이 옳다는 것을 알려 주어야합니까?
Joey Pabalinas

첫 번째 의견에 따라 답변을 업데이트했습니다. 그러나 나는 "당신이 무언가를 인스턴스화 할 때, 컴파일러에게 그 것이 존재한다고 말해야합니다"라는 의견에 동의하지 않습니다. 인스턴스화 할 때 항상 lhs 유형을 지정하지는 않습니다. 예 : a = 10. 여기에 "특성"을 지정하지 않았습니다.
SRIDHARAN

4

정의는 실제 함수 작성을 의미하고 선언은 예를 들어 간단한 선언 함수를 의미합니다.

void  myfunction(); //this is simple declaration

void myfunction()
{
 some statement;    
}

이것은 함수 myfunction의 정의입니다.


1
그리고 유형과 객체는 어떻습니까?
sbi

4

경험 법칙 :

  • 선언은 어떻게 메모리에 변수의 데이터를 해석하는 컴파일러를 알려줍니다. 이것은 모든 액세스에 필요합니다.

  • 정의는 변수가 기존 만들 수있는 메모리를 보유하고 있습니다. 이것은 처음 액세스하기 전에 정확히 한 번만 발생해야합니다.


2
이것은 객체에만 적용됩니다. 유형과 기능은 어떻습니까?
궤도에서 가벼움 경주

4

명사를 이해하려면 먼저 동사에 초점을 맞추겠습니다.

선언 -공식적으로 발표; 선포하다

정의 -명확하고 완전하게 (누군가 또는 무언가) 보여 주거나 묘사하기

따라서 무언가를 선언하면 그게 무엇인지 말해 주면됩니다 .

// declaration
int sum(int, int);

이 줄 sum 유형의 두 인수를 사용하여을 int반환하는 C 함수를 선언 합니다 int. 그러나 아직 사용할 수 없습니다.

실제로 작동 하는 방식 을 제공하면 바로 그 정의입니다.

// definition
int sum(int x, int y)
{
    return x + y;
}

3

선언과 정의의 차이점을 이해하려면 어셈블리 코드를 확인해야합니다.

uint8_t   ui8 = 5;  |   movb    $0x5,-0x45(%rbp)
int         i = 5;  |   movl    $0x5,-0x3c(%rbp)
uint32_t ui32 = 5;  |   movl    $0x5,-0x38(%rbp)
uint64_t ui64 = 5;  |   movq    $0x5,-0x10(%rbp)
double   doub = 5;  |   movsd   0x328(%rip),%xmm0        # 0x400a20
                        movsd   %xmm0,-0x8(%rbp)

그리고 이것은 정의 일뿐입니다 :

ui8 = 5;   |   movb    $0x5,-0x45(%rbp)
i = 5;     |   movl    $0x5,-0x3c(%rbp)
ui32 = 5;  |   movl    $0x5,-0x38(%rbp)
ui64 = 5;  |   movq    $0x5,-0x10(%rbp)
doub = 5;  |   movsd   0x328(%rip),%xmm0        # 0x400a20
               movsd   %xmm0,-0x8(%rbp)

보시다시피 아무것도 변하지 않습니다.

선언은 컴파일러에서만 사용되는 정보를 제공하므로 정의와 다릅니다. 예를 들어 uint8_t는 컴파일러에게 asm 함수 movb를 사용하도록 지시합니다.

저거 봐:

uint def;                  |  no instructions
printf("some stuff...");   |  [...] callq   0x400450 <printf@plt>
def=5;                     |  movb    $0x5,-0x45(%rbp)

선언은 실행할 명령이 없기 때문에 동등한 명령이 아닙니다.

또한 선언은 컴파일러에게 변수의 범위를 알려줍니다.

선언은 컴파일러가 변수를 올바르게 사용하고 일부 메모리가 특정 변수에 얼마나 오래 사용되는지 설정하기 위해 사용하는 정보라고 말할 수 있습니다.


2

가능한 가장 일반적인 용어로 선언은 스토리지가 할당되지 않은 식별자이고 정의는 실제로 선언 된 식별자에서 스토리지를 할당한다고 말할 수 있습니까?

흥미로운 생각 중 하나는 클래스 또는 함수가 유형 정보와 연결될 때까지 템플릿이 스토리지를 할당 할 수 없다는 것입니다. 템플릿 식별자는 선언 또는 정의입니까? 스토리지가 할당되지 않았기 때문에 선언이어야하며 템플릿 클래스 또는 함수를 '프로토 타이핑'하기 만하면됩니다.


1
정의 자체가 틀린 것은 아니지만 "스토리지 정의"는 함수 정의와 관련하여 항상 어색해 보입니다. 템플릿에 관하여 : 이것은 template<class T> struct foo;템플릿 선언 이며, 이것도 마찬가지입니다 template<class T> void f();. 템플릿 정의는 클래스 / 함수 정의를 같은 방식으로 미러링합니다. ( 템플릿 이름유형 또는 함수 이름 이 아닙니다 .이를 볼 수있는 곳은 템플릿을 다른 템플릿의 유형 매개 변수로 전달할 수없는 경우입니다. 유형 대신 템플리트를 전달하려면 템플릿 템플리트 매개 변수가 필요합니다. )
sbi

특히 함수 정의와 관련하여 '스토리지 정의'가 어색하다는 데 동의했습니다. 선언은 int foo ()이고 정의는 int foo () {// some code here ..}입니다. 나는 보통 친숙한 개념으로 작은 뇌를

2

비슷한 답변을 여기에서 찾으십시오 : C의 기술 면접 질문 .

선언은 프로그램에 이름을 제공합니다; 정의 프로그램 내의 기업의 고유의 설명 (예, 타입 인스턴스, 및 기능)을 제공한다. 지정된 범위에서 선언을 반복 할 수 있으며 지정된 범위에 이름이 도입됩니다.

다음과 같은 경우를 제외하고 선언은 정의입니다.

  • 선언은 본문을 지정하지 않고 함수를 선언합니다.
  • 선언에는 extern 지정자가 포함되며 초기화 프로그램이나 함수 본문은 없습니다.
  • 선언은 클래스 정의가없는 정적 클래스 데이터 멤버의 선언입니다.
  • 선언은 클래스 이름 정의입니다.

다음과 같은 경우가 아니면 정의는 선언입니다.

  • 정의는 정적 클래스 데이터 멤버를 정의합니다.
  • 정의는 비 인라인 멤버 함수를 정의합니다.

1

이것은 정말 치즈 소리처럼 들리지만 용어를 머리 속에 똑바로 유지할 수있는 가장 좋은 방법입니다.

선언 : 그림 토머스 제퍼슨 (Thomas Jefferson)이 연설을합니다. "저는이 소스 코드에이 푸가 존재한다는 것을 선언합니다 !!!"

정의 : 사전을 그림으로, 당신은 Foo를 찾고 있으며 그것이 실제로 의미하는 바입니다.


1

선언은 컴파일러에 심볼 이름을 제공합니다. 정의는 기호를위한 공간을 할당하는 선언입니다.

int f(int x); // function declaration (I know f exists)

int f(int x) { return 2*x; } // declaration and definition

1

GNU C 라이브러리 매뉴얼에 따르면 ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )

C에서 선언은 단순히 함수 또는 변수가 존재한다는 정보를 제공하고 해당 유형을 제공합니다. 함수 선언의 경우 인수 유형에 대한 정보도 제공 될 수 있습니다. 선언의 목적은 컴파일러가 선언 된 변수 및 함수에 대한 참조를 올바르게 처리 할 수 ​​있도록하는 것입니다. 반면에 정의는 실제로 변수에 스토리지를 할당하거나 함수의 기능을 말합니다.


0

선언과 정의의 개념은 extern 스토리지 클래스를 사용할 때 정의가 다른 위치에 있고 로컬 코드 파일 (페이지)에 변수를 선언하기 때문에 함정을 형성합니다. C와 C ++의 한 가지 차이점은 C에서는 선언이 함수 나 코드 페이지의 시작 부분에서 정상적으로 수행된다는 것입니다. C ++에서는 그렇지 않습니다. 선택한 장소에서 신고 할 수 있습니다.


1
이것은 선언과 정의를 혼동하고 명백한 잘못입니다.
sbi

0

내가 가장 좋아하는 예는 "int Num = 5"입니다. 여기서 변수는 1입니다. int로 정의 2. Num으로 선언하고 3, 값 5로 인스턴스화합니다. 우리

  • 내장 또는 클래스 또는 구조체 일 수있는 객체의 유형을 정의하십시오.
  • 객체의 이름을 선언하여 변수, 함수 등을 포함한 이름을 가진 모든 것이 선언되었습니다.

클래스 또는 구조체를 사용하면 나중에 사용될 때 객체가 정의되는 방식을 변경할 수 있습니다. 예를 들어

  • 구체적으로 정의되지 않은 이종 변수 또는 배열을 선언 할 수 있습니다.
  • C ++에서 오프셋을 사용하면 선언 된 이름이없는 객체를 정의 할 수 있습니다.

프로그래밍을 배우면이 두 용어는 종종 동시에 두 가지를 수행하기 때문에 혼란스러워합니다.


왜 많은 사람들이 sbi의 답변을 찬성했는지 이해하지 못합니다. 나는 bjhend의 대답을 찬성했습니다. 내가 4 년 만에 처음으로 그런 사람임을 알게되어 슬 sad습니다.
Jason K.

0

실행 가능한 생성 단계 :

(1) 전 처리기-> (2) 변환기 / 컴파일러-> (3) 링커

2 단계 (번역기 / 컴파일러)에서 코드의 선언문은 컴파일러에게 향후에 사용할 것들을 알려주고 나중에 정의를 찾을 수 있음을 의미합니다.

번역기 확인 : 무엇입니까? 선언을 의미

그리고 (3) 단계 (링커)는 사물을 묶는 정의가 필요합니다

링커는 다음을 확인하십시오 . 정의를 의미


0

K & R (제 2 판)에 뿌려진 명확한 정의가 있습니다. 그것들을 한곳에 놓고 하나의 것으로 읽는 데 도움이됩니다.

"정의"는 변수가 생성되거나 스토리지가 할당 된 장소를 나타냅니다. "선언 (declaration)"은 변수의 특성이 명시되어 있지만 스토리지가 할당되지 않은 장소를 의미합니다. [피. 33]

...

외부 변수 선언정의 를 구분하는 것이 중요합니다 . 선언은 변수의 속성 (주로 그 유형)을 알려줍니다. 정의는 또한 스토리지가 옆으로 설정되도록합니다. 줄이

int sp;
double val[MAXVAL]

어떤 기능의 외부 표시들은 정의 외부 변수 sp하고 val, 원인이 따로 저장해야하고, 또한 소스 파일의 나머지 선언 역할을한다.

반면에 선

extern int sp;
extern double val[];

선언 소스 파일의 나머지 spint및 그 valA는 double(크기가 다른 판정) 배열되지만 그들에 대한 변수 또는 예비 저장을 생성하지 않는다.

소스 프로그램을 구성하는 모든 파일 중에서 외부 변수의 정의 는 하나만 있어야합니다 . ... 배열 크기는 정의로 지정해야하지만 extern선언 에서는 선택 사항입니다 . [pp. 80-81]

...

선언은 각 식별자에 주어진 해석을 지정합니다. 반드시 식별자와 관련된 저장소를 예약 할 필요는 없습니다. 스토리지를 예약하는 선언을 정의 라고 합니다 . [피. 210]


-1

선언은 다음과 같이 변수에 이름과 유형을 지정합니다 (변수 선언의 경우).

int i;

또는 이름, 반환 유형 및 매개 변수 유형을 본문이없는 함수에 제공합니다 (함수 선언의 경우). 예 :

int max(int, int);

반면 정의는 변수에 값을 할당하는 것을 의미합니다 (변수 정의의 경우). 예 :

i = 20;

또는 함수에 본문 (기능)을 제공 / 추가하는 것을 함수 정의라고합니다. 예 :

int max(int a, int b)
{
   if(a>b)   return a;
   return b;  
}

많은 시간 선언 및 정의는 다음과 같이 함께 수행 될 수 있습니다.

int i=20;

과:

int max(int a, int b)
{
    if(a>b)   return a;
    return b;    
} 

위의 경우 변수 i및을 정의하고 선언합니다 function max().


변수 / 함수에 값 / 본문을 할당하는 경우 실제 정의 평균 반면 선언 수단은 변수 / 함수에 이름, 유형을 제공합니다
Puneet Purohit

값을 할당하지 않고 무언가를 정의 할 수 있습니다.
궤도에서 가벼움 경주

1
: 그냥이 같은int x;
궤도의 밝기 경주

그것의 정의가 아닌 변수 x의 선언
Puneet Purohit

2
아니요, 둘 다입니다. 정의와 초기화를 혼동하고 있습니다.
궤도에서 가벼움 경주
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.