V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Sherlockhlt
V2EX  ›  程序员

是返回一个结构指针好还是修改指针参数好?

  •  
  •   Sherlockhlt · 2013-01-12 10:56:52 +08:00 · 4137 次点击
    这是一个创建于 4340 天前的主题,其中的信息可能已经有所发展或是发生改变。
    在C中函数返回数据的时候,一般可以通过返回一个结构指针或者直接设置一个指针参数,把这个指针参数指向要返回的数据。
    我经常看到有些API(比如Openssl)都是两种返回方式都实现的,这样子会不会很冗余?
    哪一种方式更好?
    15 条回复    1970-01-01 08:00:00 +08:00
    Radeon
        1
    Radeon  
       2013-01-12 11:02:58 +08:00   ❤️ 1
    库函数不要返回自己"malloc"出来的数据,原因是客户代码和库函数有可能不使用一致的内存管理器

    如果是自己的代码内部,又都使用标准的C的malloc(),可以用第一种方式返回数据
    Radeon
        2
    Radeon  
       2013-01-12 11:10:49 +08:00
    补充一下,有时候库函数确实需要返回大小在调用前不确定的数据,由于大小不确定,所以调用方很难提前分配

    方法有二
    1. 提供一个查询函数,查询返回数据有多大,还是由调用方分配
    2. 提供一个释放内存的函数,这样库函数可以安心用自己的内存管理器来动态分配内存
    Sherlockhlt
        3
    Sherlockhlt  
    OP
       2013-01-12 11:49:34 +08:00
    @Radeon
    什么情况下会使用不一致的内存管理器呢?
    Radeon
        4
    Radeon  
       2013-01-12 11:54:56 +08:00
    @Sherlockhlt 原因有好几种
    1. 标准的malloc()不够优化。对于openssl这种lib来说,自己搞一套内存管理器,甚至关键路径用汇编都很正常
    2. 库函数已经静态链接某一特定版本的malloc()了,用户代码自己可以用另一个版本。一个进程里存在两套以上的内存管理器互不干扰,虽然C语言的入门书不会提,但是是完全正常的。而且实际中的复杂应用中也很常见
    3. 库函数实际上是OS的API。Kernel里的内存管理器和User land的自然不一样,想一样也不可能
    Radeon
        5
    Radeon  
       2013-01-12 11:59:27 +08:00
    很多C语言的初学者以为malloc()是最底层的函数之一。很遗憾,不是。malloc()只是OS提供的user land内存管理API的二道贩子而已
    Soichir
        6
    Soichir  
       2013-01-13 10:18:25 +08:00
    lz能不能举一个两种方式的例子。
    为什么我觉着 返回一个结构指针 和 修改指针 参数是一个意思。。。
    thx
    bombless
        7
    bombless  
       2013-01-13 10:47:07 +08:00
    bombless
        8
    bombless  
       2013-01-13 10:48:36 +08:00
    大约是上贴这个意思吧……手贱直接点了回复……
    Sherlockhlt
        9
    Sherlockhlt  
    OP
       2013-01-13 11:13:14 +08:00
    @Soichir
    @bombless

    对,就是这个意思。不过有一点我不是很明白,为什么要
    void modify_pointer(int **p){
    *p = (int*)malloc(sizeof(int));
    }
    而不是
    void modify_pointer(int *p){
    p = (int*) malloc(sizeof(int));
    }
    yuzhigang33
        10
    yuzhigang33  
       2013-01-13 12:36:14 +08:00
    @Sherlockhlt 第二个改变不了指针的值啊,形参。如果在外面定义int *p1 = null; 把p1传进去,出来后,p1还是null。
    Sherlockhlt
        11
    Sherlockhlt  
    OP
       2013-01-13 12:45:21 +08:00
    @yuzhigang33
    原来如此
    xuan_lengyue
        12
    xuan_lengyue  
       2013-01-13 13:07:52 +08:00
    这玩意用Objective-C来类比可能更好解释。
    Objective-C当中一般alloc的变量都是需要在稍后手动release的,
    而非alloc函数生成的变量一般就无需稍后手动release。
    其实就是约定俗成的,这块内存到底谁来管的问题。
    bombless
        13
    bombless  
       2013-01-15 10:25:57 +08:00
    看了一下回复,我想到一点:返回值最好用来指示操作是否成功,因此最好在参数列表中留一个指针的指针用于返回一个缓冲区地址。


    这关键还是代码风格的问题:有的 C 函数是没有参数列表或者说参数列表是一个 void 。
    对这样的函数最自然的做法就是用返回值来指示操作是否成功。
    为了与这样的函数统一,最好所有的函数都用返回值来指示操作是否成功。


    对于有一些函数只需要返回一个缓冲区地址的函数,可以用返回空指针的做法来指示操作失败;但如果剩余的 API 函数高度统一,那么这个函数就成为了特例并成为一个污点。


    返回空指针的做法还有一个很大的缺陷:它不符合一些编译系统的语义,所以无法让原来的API自然的扩展到一些新平台,从而在 API 的移植上留下污点。而许多平台例如 CORBA、OpenCl 上的 API 都有这样的需求。

    例如我很赞赏的 Scala ,虽然它也有空引用,但许多时候类似的语义靠 Option 类来表达,因此它就在与返回空指针来指示操作失败的做法上需要协调一下,在美学上难免带来一些招致争执的考量。
    xdeng
        14
    xdeng  
       2013-01-15 10:43:04 +08:00
    如果是制作成dll库 或者lib库 就需要提供dll库 或者lib库 自己内部的free
    最明显的是vc debug版的free 和 release版的free 不能通用。
    xdeng
        15
    xdeng  
       2013-01-15 10:44:20 +08:00
    看具体情况的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1071 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:22 · PVG 03:22 · LAX 11:22 · JFK 14:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.