c_lang_Reference_040820_01

本文主要面向Delphi程序员,介绍了C语言中指针的相关知识。阐述了指针编程的优点,如提高编译和执行速度、实现双向数据通讯等。还介绍了指针的运算、与指针有关的各种说明及意义,以及阅读组合说明符的规则等内容。

文字来源 VC世界--C语言教室

自我存档,也献给和我一样的DElphi程序员

1. 指针是C语言中一个重要的组成部分,使用指针编程有以下优点:
(1)提高程序的编译效率和执行速度。
(2)通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯。
(3)可以实现动态的存储分配。
(4)便于表示各种数据结构,编写高质量的程序。

2. 指针的运算
(1)取地址运算符&:求变量的地址
(2)取内容运算符*:表示指针所指的变量
(3)赋值运算
·把变量地址赋予指针变量
·同类型指针变量相互赋值
·把数组,字符串的首地址赋予指针变量
·把函数入口地址赋予指针变量
(4)加减运算
对指向数组,字符串的指针变量可以进行加减运算,如p+n,p-n,p++,p--等。对指向同一数组的两个指针变量可以相减。对指向其它类型的指针变量作加减运算是无意义的。
(5)关系运算
指向同一数组的两个指针变量之间可以进行大于、小于、 等于比较运算。指针可与0比较,p==0表示p为空指针。

3. 与指针有关的各种说明和意义见下表。
int *p;     p为指向整型量的指针变量
int *p[n];   p为指针数组,由n个指向整型量的指针元素组成。
int (*p)[n];  p为指向整型二维数组的指针变量,二维数组的列数为n
int *p()    p为返回指针值的函数,该指针指向整型量
int (*p)()   p为指向函数的指针,该函数返回整型量
int **p     p为一个指向另一指针的指针变量,该指针指向一个整型量。

4. 有关指针的说明很多是由指针,数组,函数说明组合而成的。
但并不是可以任意组合,例如数组不能由函数组成,即数组元素不能是一个函数;函数也不能返回一个数组或返回另一个函数。例如
int a[5]();就是错误的。

5. 关于括号
在解释组合说明符时, 标识符右边的方括号和圆括号优先于标识符左边的“*”号,而方括号和圆括号以相同的优先级从左到右结合。但可以用圆括号改变约定的结合顺序。

6. 阅读组合说明符的规则是“从里向外”。
从标识符开始,先看它右边有无方括号或园括号,如有则先作出解释,再看左边有无*号。 如果在任何时候遇到了闭括号,则在继续之前必须用相同的规则处理括号内的内容。例如:
int*(*(*a)())[10]
↑ ↑↑↑↑↑↑
7 6 4 2 1 3 5
上面给出了由内向外的阅读顺序,下面来解释它:
(1)标识符a被说明为;
(2)一个指针变量,它指向;
(3)一个函数,它返回;
(4)一个指针,该指针指向;
(5)一个有10个元素的数组,其类型为;
(6)指针型,它指向;
(7)int型数据。
因此a是一个函数指针变量,该函数返回的一个指针值又指向一个指针数组,该指针数组的元素指向整型量。

<think> 在Java中,并没有直接等同于C/C++的`__FUNCTION__`宏的内置功能。不过,Java提供了一些机制来获取类似的信息,主要是通过`StackTraceElement`类或者使用反射API。以下是几种常见的方法: 1. **使用`Thread.currentThread().getStackTrace()`** 可以通过当前线程的堆栈跟踪来获取当前执行的方法名。 示例代码: ```java public class FunctionNameExample { public static void main(String[] args) { String methodName = new Object(){}.getClass().getEnclosingMethod().getName(); System.out.println("Current method: " + methodName); // 输出:main new FunctionNameExample().exampleMethod(); } public void exampleMethod() { String methodName = Thread.currentThread().getStackTrace()[1].getMethodName(); System.out.println("Current method: " + methodName); // 输出:exampleMethod } } ``` 注意:`Thread.currentThread().getStackTrace()`返回的是一个`StackTraceElement`数组,其中索引0表示栈顶(当前方法),索引1表示调用当前方法的方法(即上一层)。但要注意,不同的JVM实现可能有所不同,所以通常我们通过遍历堆栈来查找合适的位置。 另一种更简洁的方式(在Java 9+中推荐使用`StackWalker`): ```java import java.lang.StackWalker; public class StackWalkerExample { public static void main(String[] args) { new StackWalkerExample().exampleMethod(); } public void exampleMethod() { StackWalker walker = StackWalker.getInstance(); String methodName = walker.walk(frames -> frames.findFirst().map(StackWalker.StackFrame::getMethodName).orElse("Unknown")); System.out.println("Current method: " + methodName); // 输出:exampleMethod } } ``` 2. **使用`Throwable`** 也可以创建一个`Throwable`对象(但不抛出)来获取堆栈信息。 示例代码: ```java public class ThrowableExample { public void exampleMethod() { String methodName = new Throwable().getStackTrace()[0].getMethodName(); System.out.println("Current method: " + methodName); } } ``` 3. **使用匿名内部类(在静态方法中)** 对于静态方法,可以使用匿名内部类来获取方法名(但这种方式只能用于非静态上下文中获取当前方法名): ```java public class AnonymousClassExample { public static void main(String[] args) { new AnonymousClassExample().exampleMethod(); } public void exampleMethod() { String methodName = new Object(){}.getClass().getEnclosingMethod().getName(); System.out.println("Current method: " + methodName); } } ``` 4. **使用AOP(面向切面编程)** 在更复杂的场景中,可以使用AOP框架(如AspectJ)在方法执行时自动捕获方法名。这种方法通常用于日志记录等横切关注点。 **总结**: - 在Java中,获取当前方法名最常用的方式是通过`Thread.currentThread().getStackTrace()`或`Throwable`的堆栈跟踪。 - 在Java 9及以上版本,推荐使用`StackWalker`,因为它更高效且更安全。 - 注意,这些方法都有一定的性能开销,因此在性能敏感的代码中应谨慎使用。 如果你需要在日志中输出当前方法名,可以考虑使用日志框架(如SLF4J、Log4j2)的占位符功能,它们通常提供了方便的方法来输出方法名。例如,在Log4j2中可以使用`%method`。 §§相关问题§§ 1. Java 9的`StackWalker`相比传统的堆栈跟踪方法有什么优势? 2. 如何在Java中获取调用者的方法名? 3. Java中是否有类似C/C++的`__LINE__`和`__FILE__`的功能? </think> 在Java中,并没有直接等同于C/C++的`__FUNCTION__`宏的内置功能,但可以通过以下方式实现类似效果: ### 1. 获取方法名(推荐方式) 使用`StackTraceElement`获取当前执行的方法名: ```java public class FunctionName { public static void main(String[] args) { new FunctionName().printMethodName(); } public void printMethodName() { String methodName = Thread.currentThread().getStackTrace()[1].getMethodName(); System.out.println("当前方法: " + methodName); // 输出: printMethodName } } ``` ### 2. 使用反射获取方法名 通过`getEnclosingMethod()`获取封装方法名: ```java import java.lang.reflect.Method; public class ReflectionExample { public static void main(String[] args) throws Exception { Method method = ReflectionExample.class.getMethod("exampleMethod"); System.out.println("方法名: " + method.getName()); // 输出: exampleMethod } public static void exampleMethod() { // 通过匿名内部类获取 String name = new Object(){}.getClass().getEnclosingMethod().getName(); System.out.println("当前方法: " + name); // 输出: exampleMethod } } ``` ### 3. Java 9+ 的`StackWalker`(最佳实践) Java 9引入了更高效的`StackWalker` API: ```java import java.lang.StackWalker; public class StackWalkerExample { public static void main(String[] args) { new StackWalkerExample().logMethodName(); } public void logMethodName() { StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); String methodName = walker.walk(frames -> frames.findFirst().map(StackWalker.StackFrame::getMethodName).orElse("未知方法") ); System.out.println("执行方法: " + methodName); // 输出: logMethodName } } ``` ### 关键区别说明 | 特性 | C/C++ `__FUNCTION__` | Java 替代方案 | |---------------------|---------------------------|------------------------------| | **获取方式** | 预处理器宏 | 运行时反射/堆栈跟踪 | | **性能影响** | 零开销 | 有运行时开销 | | **返回内容** | 当前函数名 | 当前方法名 | | **编译时确定** | ✓ | ✗ (运行时确定) | | **线程安全** | ✓ | ✓ | ### 实际应用场景 1. **日志记录**:自动添加调用方法名 ```java void processData() { logger.debug("进入方法: {}", getCurrentMethodName()); // ...业务逻辑... } ``` 2. **调试信息**:异常处理中自动添加上下文 ```java try { riskyOperation(); } catch (Exception e) { throw new RuntimeException("在" + getMethodName() + "中出错", e); } ``` 3. **AOP编程**:结合Spring AOP实现自动方法追踪 ```java @Aspect public class LoggingAspect { @Before("execution(* com.example..*.*(..))") public void logMethod(JoinPoint joinPoint) { System.out.println("调用方法: " + joinPoint.getSignature().getName()); } } ``` > **性能提示**:在生产环境中频繁获取方法名会影响性能,建议仅在调试/日志场景使用。对于高性能场景,可使用`-XX:-OmitStackTraceInFastThrow` JVM参数优化[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值