ความหมายของทั้งคู่ทำให้ฉันหลง
ความหมายของทั้งคู่ทำให้ฉันหลง
คำตอบ:
ประกาศแนะนำตัวระบุและอธิบายชนิดไม่ว่าจะเป็นประเภทวัตถุหรือฟังก์ชั่น การประกาศคือสิ่งที่คอมไพเลอร์จำเป็นต้องยอมรับการอ้างอิงถึงตัวระบุนั้น นี่คือการประกาศ:
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
นิยามจริง instantiates การดำเนินการ / ตัวระบุนี้ มันเป็นสิ่งที่ตัวเชื่อมโยงความต้องการเพื่อการอ้างอิงการเชื่อมโยงไปยังหน่วยงานเหล่านั้น เหล่านี้เป็นคำจำกัดความที่สอดคล้องกับการประกาศข้างต้น:
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 แล้วให้ตัวอย่าง ในหมู่พวกเขา:
[ตัวอย่าง: [... ] struct S {int a; int b; }; // กำหนด S, S :: a, และ S :: b [... ] struct S; // ประกาศ S - ยกตัวอย่าง
เพื่อรวมขึ้น: c ++ มาตรฐานพิจารณาstruct x;
จะเป็นประกาศและนิยาม (กล่าวอีกนัยหนึ่งคือ"การประกาศไปข้างหน้า" การเรียกชื่อผิดเนื่องจากไม่มีการประกาศคลาสรูปแบบอื่นใน C ++)struct x {};
ขอบคุณlitb (โยฮันเนสชอบ)ผู้ขุดบทและบทร้อยกรองจริง ๆ ในคำตอบของเขา
extern int i
/ ระบุ i
คุณสามารถมีได้มากextern int i
ในแต่ละหน่วยรวบรวมตามที่คุณต้องการ int i
อย่างไรก็ตามเป็นคำจำกัดความ มันหมายถึงพื้นที่สำหรับจำนวนเต็มที่จะอยู่ในหน่วยการแปลนี้และแนะนำให้ linker เพื่อเชื่อมโยงการอ้างอิงทั้งหมดไปยังi
หน่วยงานนี้ หากคุณมีคำจำกัดความเหล่านี้มากกว่าหรือน้อยกว่าหนึ่งตัวลิงก์จะบ่น
int i;
ในขอบเขตไฟล์ / โกลบอลหรือขอบเขตการทำงานเป็นนิยามทั้งใน C และ C ++ ใน C เพราะมันจัดสรรหน่วยเก็บข้อมูลและใน 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
คำหลักโดยไม่มี initializer หรือเนื้อหาของฟังก์ชัน:
extern const int i = 0; // defines i
extern int j; // declares j
extern "C"
{
void foo(); // declares foo
}
... หรือเป็นคำสั่งtypedef
หรือusing
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
ตอนนี้ด้วยเหตุผลใหญ่ว่าทำไมจึงเป็นเรื่องสำคัญที่จะต้องเข้าใจความแตกต่างระหว่างการประกาศและคำจำกัดความ: กฎความหมายเดียว จากส่วน 3.2.1 ของมาตรฐาน C ++:
ไม่มีหน่วยการแปลใดที่จะมีคำจำกัดความของตัวแปรฟังก์ชั่นประเภทคลาสประเภทการแจกแจงหรือเทมเพลตมากกว่าหนึ่งรายการ
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
แล้วอย่ายกตัวอย่างนิยามของสมาชิกจากเทมเพลตหลัก แต่ใช้นิยามที่พบที่อื่น" เพื่อให้เป็นคำจำกัดความคุณต้องจัดหา initializer
template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.
การประกาศ
การประกาศบอกคอมไพเลอร์ว่ามีองค์ประกอบของโปรแกรมหรือชื่ออยู่ การประกาศจะแนะนำชื่อหนึ่งชื่อขึ้นไปในโปรแกรม การประกาศสามารถเกิดขึ้นได้มากกว่าหนึ่งครั้งในโปรแกรม ดังนั้นคลาส, โครงสร้าง, ชนิดที่แจกแจงและประเภทอื่น ๆ ที่ผู้ใช้กำหนดสามารถประกาศสำหรับแต่ละหน่วยการรวบรวม
คำนิยาม
คำจำกัดความระบุรหัสหรือข้อมูลที่ชื่ออธิบาย ต้องประกาศชื่อก่อนจึงจะสามารถใช้งานได้
class foo {};
เป็นคำจำกัดความของคลาสใช่มั้ย
จากมาตรฐาน C99, 6.7 (5):
การประกาศระบุการตีความและคุณสมบัติของชุดของตัวระบุ นิยามของตัวระบุเป็นประกาศสำหรับตัวบ่งชี้ที่ว่า:
จากมาตรฐาน C ++, 3.1 (2):
การประกาศเป็นคำนิยามเว้นแต่ว่ามันจะประกาศฟังก์ชั่นโดยไม่ได้ระบุร่างกายของฟังก์ชั่นมันมีตัวระบุ extern หรือข้อกำหนดการเชื่อมโยงและไม่เริ่มต้นหรือฟังก์ชั่นร่างกายมันประกาศสมาชิกข้อมูลคงที่ในการประกาศระดับมันเป็น การประกาศชื่อคลาสหรือเป็นการประกาศ typedef การประกาศใช้หรือการใช้คำสั่ง
จากนั้นก็มีตัวอย่างบางส่วน
น่าสนใจมาก (หรือไม่ แต่ฉันแปลกใจเล็กน้อยกับมัน) typedef int myint;
เป็นคำจำกัดความใน C99 แต่มีการประกาศใน C ++ เท่านั้น
typedef
นั่นไม่ได้หมายความว่าจะสามารถทำซ้ำใน C ++ แต่ไม่ใช่ใน 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) สิ่งเหล่านี้จะเป็นคำจำกัดความเสมอ
ความหมายหมายถึงฟังก์ชั่นที่เกิดขึ้นจริงเขียนและประกาศหมายถึงฟังก์ชั่นประกาศง่าย ๆ สำหรับเช่น
void myfunction(); //this is simple declaration
และ
void myfunction()
{
some statement;
}
นี่คือนิยามของฟังก์ชั่น myfunction
หลักการง่ายๆ:
การประกาศบอกคอมไพเลอร์วิธีการตีความข้อมูลของตัวแปรในหน่วยความจำ สิ่งนี้จำเป็นสำหรับการเข้าถึงทุกครั้ง
นิยามขอสงวนหน่วยความจำที่จะทำให้ตัวแปรที่มีอยู่ สิ่งนี้จะต้องเกิดขึ้นอย่างแน่นอนหนึ่งครั้งก่อนการเข้าถึงครั้งแรก
เพื่อให้เข้าใจคำนามให้เน้นคำกริยาก่อน
ประกาศ - ประกาศอย่างเป็นทางการ; ประกาศ
define - เพื่อแสดงหรืออธิบาย (บางคนหรือบางสิ่ง) อย่างชัดเจนและครบถ้วน
ดังนั้นเมื่อคุณประกาศอะไรคุณแค่บอกว่ามันคืออะไร
// declaration
int sum(int, int);
บรรทัดนี้ประกาศฟังก์ชัน C เรียกsum
ว่าใช้เวลาสองขัดแย้งของประเภทและส่งกลับint
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
ประกาศให้ชื่อโปรแกรม; นิยามให้คำอธิบายที่ไม่ซ้ำกันของกิจการ (เช่นชนิดเช่นและฟังก์ชั่น) ภายในโปรแกรม การประกาศสามารถทำซ้ำในขอบเขตที่กำหนดโดยจะแนะนำชื่อในขอบเขตที่กำหนด
การประกาศเป็นคำนิยามเว้นแต่:
คำจำกัดความคือการประกาศเว้นแต่:
นี่เป็นเสียงที่วิเศษจริงๆ แต่มันเป็นวิธีที่ดีที่สุดที่ฉันสามารถรักษาคำศัพท์ไว้ในหัวของฉันได้:
คำแถลง: รูปภาพโทมัสเจฟเฟอร์สันกล่าวสุนทรพจน์ ... "ฉันขอประกาศว่านี่เป็นเรื่องโกหกในรหัสแหล่งที่มานี้!"
คำจำกัดความ: รูปภาพพจนานุกรมคุณกำลังค้นหา Foo และสิ่งที่มันหมายถึงจริง
การประกาศแสดงชื่อสัญลักษณ์ให้คอมไพเลอร์ คำจำกัดความคือการประกาศที่จัดสรรพื้นที่สำหรับสัญลักษณ์
int f(int x); // function declaration (I know f exists)
int f(int x) { return 2*x; } // declaration and definition
ตามคู่มือห้องสมุด GNU C ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )
ใน C การประกาศให้ข้อมูลที่ฟังก์ชันหรือตัวแปรมีอยู่และให้ชนิดของมันเท่านั้น สำหรับการประกาศฟังก์ชันข้อมูลเกี่ยวกับประเภทของอาร์กิวเมนต์อาจถูกจัดเตรียมไว้เช่นกัน วัตถุประสงค์ของการประกาศคือการอนุญาตให้คอมไพเลอร์ประมวลผลการอ้างอิงตัวแปรและฟังก์ชั่นที่ประกาศอย่างถูกต้อง ในทางกลับกันนิยามจะจัดสรรหน่วยเก็บสำหรับตัวแปรหรือบอกว่าฟังก์ชันทำอะไร
แนวคิดของการประกาศและการนิยามจะก่อให้เกิดข้อผิดพลาดเมื่อคุณใช้คลาสหน่วยเก็บข้อมูลภายนอกเนื่องจากคำจำกัดความของคุณจะอยู่ในตำแหน่งอื่นและคุณจะประกาศตัวแปรในไฟล์รหัสท้องถิ่นของคุณ (หน้า) ข้อแตกต่างอย่างหนึ่งระหว่าง C และ C ++ คือใน C คุณการประกาศจะทำตามปกติที่จุดเริ่มต้นของหน้าที่หรือโค้ดเพจ ใน C ++ มันไม่ใช่อย่างนั้น คุณสามารถประกาศ ณ สถานที่ที่คุณเลือก
ตัวอย่างที่ฉันชอบคือ "int Num = 5" ที่นี่ตัวแปรของคุณคือ 1 กำหนดเป็น int 2 ซึ่งประกาศเป็น Num และ 3 สร้างอินสแตนซ์ที่มีค่าห้า เรา
คลาสหรือโครงสร้างช่วยให้คุณเปลี่ยนวิธีการที่วัตถุจะถูกกำหนดเมื่อมีการใช้ในภายหลัง ตัวอย่างเช่น
เมื่อเราเรียนรู้การเขียนโปรแกรมคำสองคำนี้มักจะสับสนเพราะเรามักจะทำทั้งสองอย่างพร้อมกัน
ขั้นตอนของการสร้างไฟล์ที่ปฏิบัติการได้:
(1) ตัวประมวลผลล่วงหน้า -> (2) ตัวแปล / คอมไพเลอร์ -> (3) ตัวเชื่อมโยง
ในขั้นตอนที่ 2 (นักแปล / คอมไพเลอร์) ข้อความประกาศในรหัสของเราบอกกับคอมไพเลอร์ว่าสิ่งเหล่านี้เราจะใช้ในอนาคตและคุณสามารถค้นหาคำจำกัดความในภายหลังความหมายคือ:
นักแปลตรวจสอบให้แน่ใจว่า: อะไรคืออะไร หมายถึงการประกาศ
และ (3) stage (linker) ต้องการคำจำกัดความเพื่อผูกสิ่งต่าง ๆ
Linker ตรวจสอบให้แน่ใจว่า: อะไรอยู่ที่ไหน หมายถึงความหมาย
มีคำจำกัดความที่ชัดเจนบางอย่างที่ปรากฏใน K&R (ฉบับที่ 2); มันจะช่วยให้พวกเขาอยู่ในที่เดียวและอ่านพวกเขาเป็นหนึ่ง:
"คำจำกัดความ" หมายถึงสถานที่ที่ตัวแปรถูกสร้างขึ้นหรือที่เก็บข้อมูลที่ได้รับมอบหมาย "การประกาศ" หมายถึงสถานที่ที่ระบุลักษณะของตัวแปร แต่ไม่มีการจัดสรรที่เก็บข้อมูล [p 33]
...
มันเป็นสิ่งสำคัญที่จะแยกแยะความแตกต่างระหว่างการประกาศของตัวแปรภายนอกและความหมาย ประกาศประกาศคุณสมบัติของตัวแปร (ส่วนใหญ่ประเภทของมัน); คำจำกัดความยังทำให้การจัดเก็บถูกตั้งค่าไว้ ถ้าเป็นเส้น
int sp; double val[MAXVAL]
ปรากฏขึ้นนอกฟังก์ชั่นใด ๆ พวกเขากำหนดตัวแปรภายนอก
sp
และval
ทำให้การจัดเก็บจะถูกเก็บไว้และยังทำหน้าที่เป็นการประกาศสำหรับส่วนที่เหลือของไฟล์ต้นฉบับที่ในทางกลับกันเส้น
extern int sp; extern double val[];
ประกาศส่วนที่เหลือของไฟล์ต้นฉบับที่
sp
เป็นint
และนั่นval
คือdouble
อาเรย์ (ซึ่งมีการกำหนดขนาดที่อื่น) แต่พวกเขาไม่ได้สร้างตัวแปรหรือสำรองที่เก็บสำหรับพวกเขาจะต้องมีคำจำกัดความเดียวของตัวแปรภายนอกในไฟล์ทั้งหมดที่ประกอบขึ้นเป็นซอร์สโปรแกรม ... ขนาดอาร์เรย์ต้องระบุด้วยคำจำกัดความ แต่เป็นทางเลือกที่มีการ
extern
ประกาศ [PP 80-81]...
การประกาศระบุการตีความที่ให้กับตัวระบุแต่ละตัว ไม่จำเป็นต้องจองพื้นที่เก็บข้อมูลที่เชื่อมโยงกับตัวระบุ การประกาศว่าการจัดเก็บข้อมูลสำรองจะเรียกว่าคำจำกัดความ [p 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;