预编译、类型定义、static、extern及函数指针

本文详细介绍了C语言中的宏定义使用方法,包括不带参数及带参数的宏定义,并探讨了条件编译的概念。此外,还讲解了static与extern关键字的作用范围,以及typedef在类型别名定义中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、宏定义

// 不带参数的宏定义
#define pai=3.14int main()
{
	int a;
	int r=6;
	a=2*pai*r// 编译前会被替换为 3.14
	return 0;
}

// 带参数的宏定义
#define pingfang(a) (a)*(a);
int main()
{
	int res = pingfang(5+5);	// 编译前会被替换为 int res = (5+5)*(5+5)
	return 0;
}

注意:
1、宏定义只会影响他后面的语句,它前面的不会被替换;
2、带参数的宏定义需要将参数和结果都加上(), 否则会出现错误;#define pingfang(a) (a*a);替换后就会变成5+5*5+5


2、条件编译
在编译前进行判断那段代码需要编译 那些不需要编译

#ifndef _WR_H_
#define _WR_H_
#include "wr.h"
#end if

二、static和extern
static:
函数 文件级私有函数,被其他文件包含了也不能使用
全局变量 文件级私有的全局变量,被其他文件包含了也不能访问
局部变量 函数内部的静态变量,函数被销毁该变量依然存在直到程序结束
extern:
全局函数 被其他文件包含了可以使用,默认情况下就是extern所以extern关键字可以省略而且不能有相同的函数民
全局变量 声明一个全局变量,默认情况下就是extern所以extern关键字可以省略,如果定义了相同的变量名那么他们是同一个变量

三、typedef

给已经存在的类型起一个新的名称

// 基本数据类型
typedef int MyInt;

// 指针
typedef char * String;

// 结构体
typedef struct
{
	char *name;
    int age;
} Person;

// 枚举
typedef enum {
    Man,
    Woman
} Sex;

// 指向函数的指针
typedef int (*MyPoint)(int, int);

指针函数:

(1)定义:返回值为一个某一类型指针的函数称为指针函数。

(2)格式:类型说明符* 函数名(形参列表);*表示返回值为一个指针或地址。

(3)程序示例如下:

#include<stdio.h>
 
int* max(int x,inty)
 
{
 
return x>y?x:y;
 
}
 
int main(int argc,const char* argv[])
 
{
 
 
 int a=3,b=4;
 
 int *p=max(3,4);
 
 printf("%p\n",p);
 
 return 0;
 
}

该函数打印输出p的地址,该函数属于值传递。

函数指针:

(1)定义:存放函数首地址的指针变量就是函数指针

(2)格式:类型说明符 (*变量名)(函数的参数列表);

(3)程序示例如下:

#include <stdio.h>
 
int sum(int x,int y)
 
{
 
return x+y;
 
}
 
int main(int argc, const char * argv[])
 
{
 
int s=0;
 
int (*p)(int a,int b); //定义函数指针
 
p = sum; //给函数指针赋值,p指向sum,sum存的就是函数的首地址。
 
        s = p(23,34);
 
printf("%d\n",s);
 
return 0;
 
}

该函数打印输出结果为57。

注意:

1、函数指针变量不能进行算术运算,这是与数组指针不一样的。

2、函数调用中*两边的括号不能少,另外,*只是一个符号,不能认为是取值运算。


<think>我们正在讨论的是C语言中`static inline`函数是否可以作为函数指针使用。 首先,回顾C语言中`static inline`函数的含义: - `static`表示该函数具有内部链接,仅在定义它的编译单元(源文件)内可见。 - `inline`是对编译器的建议,建议在调用处内联展开该函数,以避免函数调用的开销。但编译器不一定内联,特别是当函数地址被获取时。 根据C标准(如C11),内联函数(inline function)可以获取其地址。如果函数被声明为`inline`,那么它必须有一个外部定义(在另一个编译单元中)或者在同一编译单元中有一个非内联的定义,否则当获取函数地址时,编译器可能无法找到函数实体。 但是,对于`static inline`函数,由于`static`关键字,该函数不需要外部定义。它只在当前编译单元内有效。因此,当我们在同一个编译单元内获取一个`static inline`函数的地址时,编译器会确保有一个函数实体存在(即使该函数被内联展开,编译器也会生成一个函数实体用于取地址的情况)。 因此,答案是:**可以**。我们可以将`static inline`函数的地址赋值给一个函数指针,并在同一个编译单元内通过该指针调用函数。 示例: ```c #include <stdio.h> static inline void my_function(int x) { printf("Value: %d\n", x); } int main() { // 定义一个函数指针,指向my_function void (*func_ptr)(int) = &my_function; // 或者直接 = my_function; // 通过函数指针调用 func_ptr(42); return 0; } ``` 上述代码是合法的。编译器会确保`my_function`有一个实体(即使它被内联,也会生成一个实体用于取地址),因此函数指针可以正常工作。 注意事项: 1. 由于`static`的作用,该函数指针只能在定义该函数的源文件内使用(即不能在其他源文件中使用这个函数指针指向这个函数,因为该函数在其他源文件不可见)。 2. 如果函数被内联,那么通过函数指针调用可能会失去内联优化(因为通过指针调用通常无法内联)。但是,这并不影响正确性。 因此,在您提供的代码中,如`dmpKernelUpdateMacEntry`等函数如果是`static inline`的,并且在同一源文件中被赋值给函数指针(如`netifFieldTbl`数组中的`updateFunc`),那么是完全可以的。 但是,请注意:如果这些函数在其他源文件中使用(比如通过头文件包含,但每个源文件都有自己的一份`static`函数副本),那么函数指针只能指向当前源文件中的函数副本。如果多个源文件都使用同一个头文件中的`static inline`函数,那么每个源文件都会有自己的函数实体,函数指针指向的是各自源文件中的实体,这通常不会造成问题,因为它们是独立的。 结论:在C语言中,`static inline`函数可以作为函数指针使用,但仅限于定义它的编译单元(即同一个源文件)内。 如果您的程序出现了coredump,可能与函数指针是否指向`static inline`函数无关,而可能是其他原因(如空指针解引用、内存越界等)。请结合之前的分析排查。 相关问题: 1. 在C语言中,`static inline`函数和`extern inline`函数有什么区别? 2. 如何避免函数指针引起的未定义行为? 3. 函数指针在C++中与在C中有何不同?</think>### 能否在 C 语言中将 `static inline` 函数用作函数指针? **可以**。在 C 语言中,`static inline` 函数完全可以作为函数指针使用,但需要理解其特性和限制: #### ✅ 工作原理 1. **`static` 的作用** - 使函数仅在当前编译单元(源文件)内可见 - 避免与其他编译单元的同名函数冲突 - 保证函数有实际地址(即使被内联优化) 2. **`inline` 的作用** - 向编译器建议内联展开(非强制) - 当获取函数地址时,编译器会自动生成函数实体 - 示例: ```c static inline void test(int x) { printf("%d\n", x); } int main() { void (*func_ptr)(int) = &test; // ✅ 合法 func_ptr(42); // ✅ 正常调用 return 0; } ``` #### ⚠️ 注意事项 1. **作用域限制** 函数指针**只能在同一源文件内使用**(因 `static` 限制): ```c // file1.c static inline void func() {...} // file2.c extern void (*ptr)() = &func; // ❌ 链接错误:func 不可见 ``` 2. **内联优化失效** 通过函数指针调用时: - 失去内联优化的性能优势 - 产生常规函数调用开销 3. **标准兼容性** - C99 及以上标准完全支持此用法 - 部分旧编译器(如 VC++)可能需特殊处理 #### 实际应用场景 ```c typedef void (*Callback)(int); static inline void fast_handler(int id) { // 高频调用的轻量级处理 } void register_callback(Callback cb) { // 接受函数指针注册 } int main() { register_callback(fast_handler); // ✅ 合法传递 return 0; } ``` #### 调试建议 若遇到 coredump: 1. 检查函数指针是否为 `NULL` ```c if (func_ptr != NULL) func_ptr(...); ``` 2. 使用 `nm` 工具验证符号存在性: ```bash nm -gC your_program | grep 'your_function' ``` 3. 通过 GDB 验证地址有效性: ```gdb (gdb) p &your_static_inline_function ``` > 此机制在 Linux 内核中广泛使用,如网络栈回调函数[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值