是返回一个结构指针好还是修改指针参数好? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
Sherlockhlt
V2EX    程序员

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

  •  
  •   Sherlockhlt 2013-01-12 10:56:52 +08:00 4528 次点击
    这是一个创建于 4687 天前的主题,其中的信息可能已经有所发展或是发生改变。
    在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     Solana     1016 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 22:50 PVG 06:50 LAX 14:50 JFK 17:50
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86