👨🏻‍💻 编程

c 语言中的声明、定义及它们的区别

在 C 语言中,声明(Declaration)和定义(Definition)是两个非常重要但容易混淆的概念。它们共同作用于变量、函数、类型等元素的使用,但它们的作用和意义有所不同。理解这两者的区别对于编写高效、可维护的代码至关重要。

1. 声明(Declaration)

声明是告诉编译器某个变量、函数或类型的存在以及它的属性(如类型),但并不分配存储空间或提供实现细节。

变量声明

变量声明告诉编译器变量的类型和名称。例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
extern int a;
extern int a;
extern int a;
  • 这里,extern 关键字表示这个变量在其他地方定义,当前文件仅仅是声明它的存在。
  • 编译器会知道 a 是一个 int 类型的变量,但它不会为 a 分配内存,因为它期待在某个地方有 a 的定义。

函数声明

函数声明告诉编译器函数的名称、返回类型以及参数类型,但不包含具体的实现。例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
int add(int, int);
int add(int, int);
int add(int, int);
  • 这只是一个函数的声明,表示 add 函数存在,它接受两个 int 类型的参数,并返回一个 int 类型的结果。
  • 编译器在链接阶段会查找函数的定义(即函数体)。

类型声明

类型声明通常通过 typedef 关键字来创建类型别名。例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
typedef unsigned long int ulong;
typedef unsigned long int ulong;
typedef unsigned long int ulong;
  • 这告诉编译器 ulongunsigned long int 的别名。

2. 定义(Definition)

定义不仅仅是告诉编译器某个元素的存在,还分配存储空间或提供具体的实现细节。定义包含了编译器执行程序所需的全部信息。

变量定义

变量定义不仅声明了变量,还分配了存储空间。例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
int a = 10;
int a = 10;
int a = 10;
  • 这不仅声明了 a 是一个 int 类型的变量,而且分配了存储空间并初始化为 10
  • 如果一个变量在全局或局部范围内只被定义一次。

函数定义

函数定义不仅声明了函数的返回类型和参数类型,还提供了函数的实现。例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
int add(int a, int b) {
return a + b;
}
int add(int a, int b) { return a + b; }
int add(int a, int b) {
    return a + b;
}
  • 这不仅声明了 add 函数的接口,还提供了具体的实现细节。
  • 编译器需要函数定义来生成可执行代码。

结构体和联合体定义

结构体和联合体定义不仅声明了它们的成员,还分配了存储空间。例如:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
struct Point {
int x;
int y;
};
struct Point { int x; int y; };
struct Point {
    int x;
    int y;
};
  • 这不仅声明了 Point 结构体,还定义了它的存储布局。

3. 声明与定义的区别

  • 存储空间:声明不会分配存储空间,定义则会。对于变量,定义分配实际的内存空间;对于函数,定义提供了实际的代码实现。
  • 数量:声明可以出现多次(通常在不同的文件中),但定义通常只能出现一次。多次定义会导致链接错误。
  • 链接性:声明通常用于跨文件的访问,而定义则是实现的具体细节。通过在头文件中声明(不定义)全局变量和函数,其他文件可以访问它们,而定义则放在一个单独的源文件中。

4. 例子

假设有两个文件 file1.cfile2.c

file1.c:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include "header.h"
int a = 10; // 变量定义
int add(int x, int y) { // 函数定义
return x + y;
}
#include "header.h" int a = 10; // 变量定义 int add(int x, int y) { // 函数定义 return x + y; }
#include "header.h"

int a = 10;  // 变量定义
int add(int x, int y) {  // 函数定义
    return x + y;
}

header.h:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
extern int a; // 变量声明
int add(int, int); // 函数声明
extern int a; // 变量声明 int add(int, int); // 函数声明
extern int a;  // 变量声明
int add(int, int);  // 函数声明

file2.c:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include "header.h"
void printSum() {
printf("%dn", add(a, 20));
}
#include "header.h" void printSum() { printf("%dn", add(a, 20)); }
#include "header.h"

void printSum() {
    printf("%dn", add(a, 20));
}
  • header.h 文件中包含了 a 变量和 add 函数的声明,使得 file2.c 可以访问它们。
  • 但真正的定义在 file1.c 中,因此编译器会将 file2.c 中的调用链接到 file1.c 中的定义。

总结

  • 声明 是告诉编译器某个变量、函数或类型的存在以及它们的属性,但不分配存储空间或提供实现。
  • 定义 则包含了声明的全部信息,并为变量分配内存或提供函数的实现。
  • 区分声明和定义对避免链接错误、保持代码模块化和易于维护至关重要。

留言

您的邮箱地址不会被公开。 必填项已用 * 标注