둘의 의미는 나를 피한다.
둘의 의미는 나를 피한다.
답변:
선언 그것을 입력, 개체 또는 함수일, 식별자를 소개하고, 형식을 설명한다. 선언은 컴파일러가 해당 식별자에 대한 참조를 수락 해야하는 것 입니다. 이들은 선언입니다 :
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) 에게 감사 합니다.
extern int i
그냥 소개 / 지정하기 때문에 선언 i
입니다. extern int i
각 컴파일 단위에 원하는만큼을 가질 수 있습니다 . int i
그러나 정의입니다. 정수가이 변환 단위에있는 공간을 나타내며 링커가 모든 i
엔티티를이 엔티티에 링크하도록 조언합니다 . 이러한 정의 중 하나 이상을 가지고있는 경우 링커가 불평합니다.
int i;
파일 / 글로벌 범위 또는 함수 범위의 @Brian 은 C 및 C ++ 모두에서 정의됩니다. C에서는 스토리지를 할당하기 때문에 C ++에서는 extern 지정자 또는 링크 지정이 없으므로 C ++에서. 이것들은 sbi가 말하는 것과 같은 것입니다. 두 경우 모두이 선언은 해당 범위에서 "i"에 대한 모든 참조가 연결되어야하는 객체를 지정합니다.
struct A { double f(int, double); double f(int, double); };
. 물론 유효하지 않습니다. 그래도 다른 곳에서는 허용됩니다. 선언 할 수는 있지만 정의 할 수없는 곳도 있습니다. void f() { void g(); }
유효하지만 다음은 아닙니다 void f() { void g() { } };
.. 템플릿이란 무엇인가? 정의 란 무엇이며 선언에는 미묘한 규칙이 있습니다. 좋은 답변은 +1입니다.
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
}
... 또는 typedef
or using
문입니다.
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
이제 선언과 정의의 차이를 이해하는 것이 중요한 이유는 바로 하나의 정의 규칙 입니다. C ++ 표준의 3.2.1 절에서 :
번역 단위에는 변수, 함수, 클래스 유형, 열거 유형 또는 템플릿에 대한 정의가 둘 이상 포함되어서는 안됩니다.
struct x {static int b = 3; };
?
b
또한 선언 하지 않는 한 예제에 대한 수정은 실제로 불법 const
입니다. stackoverflow.com/a/3536513/1858225 및 daniweb.com/software-development/cpp/threads/140739/…를 참조하십시오 .
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.
선언
선언은 컴파일러에게 프로그램 요소 또는 이름이 존재 함을 알려줍니다. 선언은 하나 이상의 이름을 프로그램에 도입합니다. 프로그램에서 선언이 두 번 이상 발생할 수 있습니다. 따라서 클래스, 구조, 열거 유형 및 기타 사용자 정의 유형을 각 컴파일 단위에 대해 선언 할 수 있습니다.
정의
정의는 이름이 설명하는 코드 또는 데이터를 지정합니다. 이름을 사용하려면 먼저 선언해야합니다.
class foo {};
인 클래스 정의는 , 그렇지?
C99 표준에서 6.7 (5) :
선언은 식별자 세트의 해석 및 속성을 지정합니다. 식별자 의 정의 는 다음과 같은 식별자에 대한 선언입니다.
C ++ 표준 3.1 (2)에서 :
선언은 함수 본문을 지정하지 않고 함수를 선언하지 않는 한 정의 이며 , extern 지정자 또는 연결 지정을 포함하고 초기화 자나 함수 본문을 포함하지 않으며 클래스 선언에서 정적 데이터 멤버를 선언합니다. 클래스 이름 선언이거나 typedef 선언, using-declaration 또는 using-directive입니다.
그런 다음 몇 가지 예가 있습니다.
흥미롭게도 (또는 약간 놀랐습니다) typedef int myint;
C99의 정의이지만 C ++의 선언 만입니다.
typedef
C99에서는 반복 할 수는 있지만 C99에서는 반복 될 수 없다는 것을 의미하지 않습니까?
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;
답변을 참조하십시오 .
struct foo {};
이 아니라 정의 입니다. 의 선언은 foo
입니다 struct foo;
. 그로부터 컴파일러는 foo
객체 를 예약 할 공간이 얼마나되는지 알지 못합니다 .
struct foo;
선언이지만 컴파일러에게 foo의 크기를 알려주지는 않습니다. 나는 그것을 struct _tagExample { int a; int b; };
정의라고 덧붙였다. 따라서 이러한 맥락에서 선언이라고 부르는 것은 잘못된 것입니다. 물론 모든 정의가 선언이기 때문에 하나이지만 정의가 아니라고 제안하는 것 같습니다. _tagExample의 정의입니다.
C ++ 11과 관련된 대답을 볼 수 없으므로 여기에 하나가 있습니다.
선언은 a / n을 선언하지 않는 한 정의입니다 .
enum X : int;
template<typename T> class MyArray;
int 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 int a;
또는extern "C" { ... };
class C { static int x; };
struct Point;
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
정의 :
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);
}
int a; //declaration; a=10; //definition
이것은 완전히 잘못되었습니다. 자동 스토리지 기간 오브젝트 (extern과 같은 다른 스토리지 클래스 지정자로 선언되지 않은 함수 정의 내에서 선언 된 오브젝트)에 대해 이야기 할 때는 항상 정의입니다.
경험 법칙 :
선언은 어떻게 메모리에 변수의 데이터를 해석하는 컴파일러를 알려줍니다. 이것은 모든 액세스에 필요합니다.
정의는 변수가 기존 만들 수있는 메모리를 보유하고 있습니다. 이것은 처음 액세스하기 전에 정확히 한 번만 발생해야합니다.
명사를 이해하려면 먼저 동사에 초점을 맞추겠습니다.
선언 -공식적으로 발표; 선포하다
정의 -명확하고 완전하게 (누군가 또는 무언가) 보여 주거나 묘사하기
따라서 무언가를 선언하면 그게 무엇인지 말해 주면됩니다 .
// declaration
int sum(int, int);
이 줄 은sum
유형의 두 인수를 사용하여을 int
반환하는 C 함수를 선언 합니다 int
. 그러나 아직 사용할 수 없습니다.
실제로 작동 하는 방식 을 제공하면 바로 그 정의입니다.
// definition
int sum(int x, int y)
{
return x + y;
}
선언과 정의의 차이점을 이해하려면 어셈블리 코드를 확인해야합니다.
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)
선언은 실행할 명령이 없기 때문에 동등한 명령이 아닙니다.
또한 선언은 컴파일러에게 변수의 범위를 알려줍니다.
선언은 컴파일러가 변수를 올바르게 사용하고 일부 메모리가 특정 변수에 얼마나 오래 사용되는지 설정하기 위해 사용하는 정보라고 말할 수 있습니다.
가능한 가장 일반적인 용어로 선언은 스토리지가 할당되지 않은 식별자이고 정의는 실제로 선언 된 식별자에서 스토리지를 할당한다고 말할 수 있습니까?
흥미로운 생각 중 하나는 클래스 또는 함수가 유형 정보와 연결될 때까지 템플릿이 스토리지를 할당 할 수 없다는 것입니다. 템플릿 식별자는 선언 또는 정의입니까? 스토리지가 할당되지 않았기 때문에 선언이어야하며 템플릿 클래스 또는 함수를 '프로토 타이핑'하기 만하면됩니다.
template<class T> struct foo;
템플릿 선언 이며, 이것도 마찬가지입니다 template<class T> void f();
. 템플릿 정의는 클래스 / 함수 정의를 같은 방식으로 미러링합니다. ( 템플릿 이름 은 유형 또는 함수 이름 이 아닙니다 .이를 볼 수있는 곳은 템플릿을 다른 템플릿의 유형 매개 변수로 전달할 수없는 경우입니다. 유형 대신 템플리트를 전달하려면 템플릿 템플리트 매개 변수가 필요합니다. )
비슷한 답변을 여기에서 찾으십시오 : C의 기술 면접 질문 .
선언은 프로그램에 이름을 제공합니다; 정의 프로그램 내의 기업의 고유의 설명 (예, 타입 인스턴스, 및 기능)을 제공한다. 지정된 범위에서 선언을 반복 할 수 있으며 지정된 범위에 이름이 도입됩니다.
다음과 같은 경우를 제외하고 선언은 정의입니다.
다음과 같은 경우가 아니면 정의는 선언입니다.
GNU C 라이브러리 매뉴얼에 따르면 ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )
C에서 선언은 단순히 함수 또는 변수가 존재한다는 정보를 제공하고 해당 유형을 제공합니다. 함수 선언의 경우 인수 유형에 대한 정보도 제공 될 수 있습니다. 선언의 목적은 컴파일러가 선언 된 변수 및 함수에 대한 참조를 올바르게 처리 할 수 있도록하는 것입니다. 반면에 정의는 실제로 변수에 스토리지를 할당하거나 함수의 기능을 말합니다.
내가 가장 좋아하는 예는 "int Num = 5"입니다. 여기서 변수는 1입니다. int로 정의 2. Num으로 선언하고 3, 값 5로 인스턴스화합니다. 우리
클래스 또는 구조체를 사용하면 나중에 사용될 때 객체가 정의되는 방식을 변경할 수 있습니다. 예를 들어
프로그래밍을 배우면이 두 용어는 종종 동시에 두 가지를 수행하기 때문에 혼란스러워합니다.
K & R (제 2 판)에 뿌려진 명확한 정의가 있습니다. 그것들을 한곳에 놓고 하나의 것으로 읽는 데 도움이됩니다.
"정의"는 변수가 생성되거나 스토리지가 할당 된 장소를 나타냅니다. "선언 (declaration)"은 변수의 특성이 명시되어 있지만 스토리지가 할당되지 않은 장소를 의미합니다. [피. 33]
...
외부 변수 선언 과 정의 를 구분하는 것이 중요합니다 . 선언은 변수의 속성 (주로 그 유형)을 알려줍니다. 정의는 또한 스토리지가 옆으로 설정되도록합니다. 줄이
int sp; double val[MAXVAL]
어떤 기능의 외부 표시들은 정의 외부 변수
sp
하고val
, 원인이 따로 저장해야하고, 또한 소스 파일의 나머지 선언 역할을한다.반면에 선
extern int sp; extern double val[];
선언 소스 파일의 나머지
sp
인int
및 그val
A는double
(크기가 다른 판정) 배열되지만 그들에 대한 변수 또는 예비 저장을 생성하지 않는다.소스 프로그램을 구성하는 모든 파일 중에서 외부 변수의 정의 는 하나만 있어야합니다 . ... 배열 크기는 정의로 지정해야하지만
extern
선언 에서는 선택 사항입니다 . [pp. 80-81]...
선언은 각 식별자에 주어진 해석을 지정합니다. 반드시 식별자와 관련된 저장소를 예약 할 필요는 없습니다. 스토리지를 예약하는 선언을 정의 라고 합니다 . [피. 210]
선언은 다음과 같이 변수에 이름과 유형을 지정합니다 (변수 선언의 경우).
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()
.
int x;