AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 78967806
Accepted
RogueGingerz
RogueGingerz
Asked: 2024-09-10 11:36:01 +0800 CST2024-09-10 11:36:01 +0800 CST 2024-09-10 11:36:01 +0800 CST

理解不透明指针

  • 772

如果这是一个显而易见的问题,我很抱歉,但在 C 中,不透明指针是否类似于 Java 接口?当我试图理解它们时,我将它们解释为与 Java 接口类似,因为它们建立了与方法/函数交互的强制性方式?所以如果我想使用不透明指针,我需要在 .h 文件中定义它,而在 .c 文件中调用它?不透明指针只定义方法/函数的签名(在 .h 文件中),而 .c 文件采用具有这些签名的函数并实现它们。

c
  • 4 4 个回答
  • 133 Views

4 个回答

  • Voted
  1. Allan Wind
    2024-09-10T11:41:12+08:002024-09-10T11:41:12+08:00

    不。不透明指针是一种设计,其中类型的实现(通常struct;可选typedef)对客户端隐藏(封装)。此模块可以以它认为合适的方式实例化类型;通常是动态分配(和释放)。客户端必须使用模块提供的函数来操作不透明指针。

    你的头文件(接口)中会有类似这样的内容:

    #ifndef FOO_H
    #define FOO_H
    
    typedef struct foo foo; // forward declaration
    foo *foo_create();
    void foo_destroy(foo *f);
    #endif
    

    然后模块实现是:

    #include <stdlib.h>
    #include "foo.h"
    
    struct foo {
       int data;
    };
    
    foo *foo_create() {
       return calloc(1, sizeof(foo));
    }
    
    void foo_destroy(foo *f) {
       free(f);
    }
    
    
    • 6
  2. Chris
    2024-09-10T13:37:19+08:002024-09-10T13:37:19+08:00

    作为 Allan Wind 答案的补充,不透明指针依赖于一个非常简单的事实:结构指针的大小都是相同的1,而它们指向的东西的大小可能差别很大。

    在 C 语言中,函数必须知道其参数、局部变量和返回值的大小。因此,在头文件中,我们无法通过值传递或返回抽象数据类型。

    因为实际数据类型是在实现文件中定义的,因此该翻译单元“知道”数据的大小,我们可以直接在那里处理抽象数据类型的值。

    只要头文件保持一致,我们就可以按照任何方式定义数据类型。可以在实现中进行改进,而不必调整客户端程序实际使用数据类型的方式。


    1指针的大小取决于硬件和软件平台。

    • 2
  3. Best Answer
    Mike Nakis
    2024-09-10T16:15:59+08:002024-09-10T16:15:59+08:00

    我将它们解释为类似于 Java 接口,因为它们建立了与方法/函数交互的强制方式

    您的解释是正确的,但缺少一个关键点:我们使用不透明指针的原因是为了隐藏结构实现的细节,以便我们可以在软件的未来版本中修改此结构,而不会破坏使用它的现有代码。

    本质上,与 Java 的类似如下:

    • 不透明指针的声明,以及接受(或返回)这种不透明指针的每个函数的声明,都对应于interfaceJava 中的。(注意:仅是声明。而不是它们的实际定义。)

    • 不透明指针指向的结构和函数定义集更像是一个具体的 Java 类implements,其接口只包含私有成员字段,因此没有人可以访问它们。

    另一个与不透明指针非常相似的概念是句柄。函数open()返回int一个文件句柄,、和方法接受这样的句柄作为参数。这个数字可以是任何东西,你不应该以任何方式解释它,也不应该期望它的值在任何特定范围内。理论上,在足够大到可以容纳指向结构的指针的系统上,文件句柄实际上可以是已转换为的结构指针。实际上,它是某个表(或类似表)的索引,该表完全由标准库(或操作系统)维护,因此你看不到它,因此不会弄乱它。read()write()close()intintFILE

    这些都是在面向对象编程发明之前人们使用的实现封装的非常原始的机制。由于没有指导原则,也没有标准的做事方式,人们到处乱搞,以各种方式破坏了封装。

    • 例如,C 标准库可以将FILE 其视为不透明指针,但出于某种原因,大多数实现选择不这样做,因为它们在头文件中定义了structfor ,而您实际上可以这样做。(请参阅Stack Overflow:Unix 中 FILE 的定义在哪里)FILE#include

    • 再举一个例子,您不应该解释文件句柄的值,但是标准流(输入、输出、错误)的文件句柄确实具有众所周知的值,本质上它们只不过是神奇的数字。

    • 2
  4. Luis Colorado
    2024-09-11T02:37:58+08:002024-09-11T02:37:58+08:00

    如果这是一个显而易见的问题,我深感抱歉,但是在 C 语言中,不透明指针是否与 Java 接口相似?

    不,这是完全不相关的事情。

    不透明指针是指向不完全指定(外部)的指针struct,用于隐藏结构的内部表示。更确切地说,它们是指向不完全定义类型(未指定的字段结构或未指定长度的数组)的指针。这样,可以使用指针,但不能使用指向的数据,因为结构内容对于编译器来说是未知的。

    typedef struct hash_table *hash_table_p;
    

    在上面的代码中,我们将类型定义hash_table_p为指向未定义结构的指针,该指针可被哈希表例程用作提供给用户的不透明数据,只需将其传递回处理结构内部作为外部不可访问字段的例程即可。

    由于指向类型的指针不可互换,因此指针引用不能混合使用,因此指向的指针struct hash_table必须始终使用真实的哈希表引用进行初始化(如果您小心谨慎,编译器将始终保证这一点)。指向不同类型的指针永远不会与指向不同类型的指针兼容(除非您对其进行强制转换)。唯一的例外是指向的指针void与任何其他类型的指针兼容。

    您可以将声明保留在外部,并在实现代码中提供 的完整定义struct hash_table。编译器将允许您声明尽可能多的引用类型的指针,但数据的内部结构对外部代码是隐藏的。结构struct hash_table通常在包含文件中定义hash_tableP.h(其中还包括外部文件),因此 C 可以模拟Modula-2 语言的DEFINITION MODULE和IMPLEMENTATION MODULE编译单元(或Ada 的package和package body)

    另一方面,Java 接口是一组方法声明,允许面向对象的类进行implement所谓的接口,因此被视为实现所有这些方法的类的对象。这在某种程度上定义了一个像对象的类,但不是从另一个类派生出来的。

    C 不能将一组过程声明关联到一种类型中,从而只有实现这些过程的实例才被视为属于单一类型(如果类型可以与类进行比较),因此 C 中没有与 Java 接口模型类似的图形。

    • 1

相关问题

  • 比 * 更快的乘法

  • 在 C 中的 scanf() 格式说明符中使用宏获取字符串长度

  • 如何将#define的数据类型设置为long double?

  • 不兼容的常量指针

  • OpenGL 中的非渐变颜色变化

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve