C 语言中没有 public 和 static 这两个关键字来修饰函数或变量,它们不是 C 语言的标准关键字。

下面我将详细解释为什么,以及 C 语言是如何实现类似功能的。
为什么 C 语言没有 public 和 static?
这主要是因为 C 语言和 Java/C# 的设计哲学和核心模型不同。
C 语言:过程式编程,关注“作用域”
C 语言是一种过程式编程语言,其核心是函数和数据结构,它没有内置的“类”和“访问控制”的概念,C 语言对变量和函数的可见性(即“访问权限”)的控制,主要通过作用域来实现。
Java/C#:面向对象编程,关注“封装”
Java 和 C# 是面向对象编程语言,其核心是类。public 和 static 是面向对象概念的一部分:

public: 访问修饰符,用于定义类、成员变量、成员函数的可见范围。public意味着任何其他代码都可以访问它,这是封装原则的体现。static: 关键字,用于声明属于类本身,而不是属于类的某个特定实例(对象)的成员,静态成员可以通过类名直接访问,无需创建对象。
C 语言如何实现类似 static 的功能?
虽然 C 语言没有 static 关键字用于类,但它有 static 关键字,并且它的含义与在 Java/C# 中有相似之处,但作用域不同,C 语言中的 static 主要用于控制链接类型和存储类型,从而影响变量或函数的生命周期和可见范围。
C 中的 static 关键字
static 在 C 中主要有两种用法:
a) 用于函数和全局变量(内部链接)
当 static 用于修饰一个全局变量或一个函数时,它会将该符号的链接类型从外部链接改为内部链接。
- 外部链接 (默认): 在一个多文件的项目中,一个全局变量或函数可以在其他任何源文件中被
extern关键字声明和使用。 - 内部链接 (
static): 这个变量或函数只在其所在的源文件(.c文件)内可见,其他文件无法访问它。
类比 private 的效果:
这非常类似于 Java 中将一个成员声明为 private,使其只在“类”内部可见,在 C 语言中,一个文件就可以被看作一个独立的“模块”或“单元”,使用 static 可以防止其他文件意外地修改或依赖你的内部实现,从而实现了封装和信息隐藏。

示例:
my_module.c
#include <stdio.h>
// 这是一个内部链接的全局变量,只在 my_module.c 中可见
static int internal_counter = 0;
// 这是一个内部链接的函数,只在 my_module.c 中可见
static void helper_function() {
internal_counter++;
printf("Helper function called. Counter is now: %d\n", internal_counter);
}
// 这是外部链接的函数,可以被其他文件使用
void public_api() {
printf("Public API is running.\n");
helper_function(); // 内部函数可以被同一个文件中的其他函数调用
}
main.c
#include <stdio.h>
// 尝试访问 internal_counter 或 helper_function 会导致编译错误
// extern int internal_counter; // 错误: 静态变量不可见
// void helper_function(); // 错误: 静态函数不可见
// 声明并使用外部链接的函数
void public_api();
int main() {
public_api(); // 可以正常调用
// helper_function(); // 编译错误!
return 0;
}
b) 用于局部变量(静态存储)
当 static 用于修饰一个函数内的局部变量时,它改变的是变量的存储类型。
- 普通局部变量: 存储在栈上,函数调用时创建,函数返回时销毁。
- 静态局部变量: 存储在静态数据区(或全局数据区),它只在程序开始时初始化一次,而不是每次函数调用时都初始化,它的生命周期贯穿整个程序,但作用域仍然限制在函数内部。
类比 Java 静态变量的效果: 这类似于 Java 中一个静态方法内部的静态变量,它会保留上一次调用的值。
示例:
#include <stdio.h>
void counter_function() {
// 普通局部变量,每次调用都会重新初始化为 0
int normal_var = 0;
normal_var++;
printf("Normal variable: %d\n", normal_var);
// 静态局部变量,只在第一次调用时初始化为 0,之后会保留上次的值
static int static_var = 0;
static_var++;
printf("Static variable: %d\n", static_var);
}
int main() {
counter_function(); // Normal: 1, Static: 1
counter_function(); // Normal: 1, Static: 2
counter_function(); // Normal: 1, Static: 3
return 0;
}
C 语言如何实现类似 public 的功能?
如前所述,C 语言没有 public 关键字,一个全局变量或函数默认就是“公共”的(具有外部链接),可以被项目中的其他文件通过 extern 声明来使用。
这相当于 Java 中默认的 public 或 protected(包内可见),如果你不希望它被其他文件使用,就用 static 关键字将其变为“私有”的(内部链接)。
C 语言中的“公共”和“私有”:
| 想要实现的效果 | C 语言实现方式 | Java/C# 实现 |
|---|---|---|
| 公共的 (Public API) | 在 .c 文件中声明一个全局变量或函数,不加 static。 |
使用 public 关键字修饰。 |
| 私有的 (Internal Implementation) | 在 .c 文件中声明一个全局变量或函数,并加上 static 关键字。 |
使用 private 关键字修饰。 |
总结与对比
| 概念 | Java / C# | C 语言 |
|---|---|---|
| 公共成员 | public |
默认(全局变量/函数,无 static) |
| 私有成员 | private |
static (用于全局变量/函数,实现内部链接) |
| 静态成员 (属于类/模块,不属于实例) | static |
static (用于函数内的局部变量,实现静态存储) |
| 静态成员 (属于模块,不属于其他模块) | private static |
static (用于全局变量/函数,实现内部链接) |
| 核心思想 | 封装:通过访问修饰符控制可见性。 | 作用域和链接:通过 static、extern 等关键字控制符号的可见范围。 |
当你看到 C 代码中的 static 关键字时,可以这样理解:
- 如果它在函数外部修饰变量或函数,它的作用是“文件私有化”,防止外部文件访问,类似
private。 - 如果它在函数内部修饰变量,它的作用是“创建一个持久化的局部变量”,类似 Java/C# 中静态方法内的静态变量。
C 语言通过这种简单而有效的方式,在没有类和访问修饰符的情况下,依然实现了良好的模块化和封装。
