关于返回结构体的函数

    【前言】写作本文,源于最近回复的 《汇编中函数返回结构体的方法》 一文。在网络上也已经有一些相关文章和相关问题,有的文章已经给出了一部分结果,但总体而言还缺少比较重要的结论。本文以分析 VC6 编译器,32 位架构为主来重复性分析这个话题。

 

    (一)不超过 8 bytes 的小结构体可以通过 EDX:EAX 返回。

    本文的范例代码取材于 《汇编中函数返回结构体的方法》一文,并在此基础上进行修改和试验。要研究的第一份代码如下,定义一个不超过 8 bytes 的小结构体,不超过 8 bytes 是因为这个结构体能够用 EDX:EAX 容纳,我们之后将看到在 release 编译时,编译器能够向返回普通基础类型那样进行返回。

 

#include <stdio.h>//不超过 8 bytes 的“小结构体”
struct A
{int a;int b;
};//返回结构体的函数
struct A add(int x, int y)
{struct A t;t.a = x * y;return t;
}int main()
{struct A t = add(3, 4);printf("t.a = %ld\n", t.a);return 0;
}

 

    首先,我们需要解决一个常见困惑,就是要明确这段代码和下面的典型错误代码的区别:

    char* get_buffer()

    {

      char buf[8];

      return buf;

    }

    上面的 get_buffer 返回的是栈上的临时变量空间,在函数返回后,其所在的空间也就被“回收/释放”了,也就是说函数返回的地址位于栈的增长方向上,是不稳定和不被保证的。

    那么返回结构体的函数则不同,你可以发现返回结构体的函数是工作正常有效的。在 add 函数中有一个临时性结构体 t,毫无疑问,t 将在 add 函数返回时被释放,但由于 t 被当做“值”进行返回,因此编译器将保证 add 的返回值对于 add 的调用者(caller)来说是有效的。

 

    另外需要明确的一点是,我个人觉得,现实里这种返回结构体的方式比较少见,后面将会看到这样做会产生临时对象和多余拷贝过程,效率不高。常见方法是传递结构体指针。但作为语言上允许的方式,有必要弄清楚编译器如何实现这种方式,而要弄清楚这个问题,需要查看汇编代码。使用 VC6 输入上述代码,下面分别给出其汇编代码。

 

    (1)debug 版本,汇编代码如下。

 

small_struct_debug
.text:00401020 add             proc near               ; CODE XREF: j_addj
.text:00401020
.text:00401020 var_48          = dword ptr -48h
.text:00401020 var_8           = dword ptr -8
.text:00401020 var_4           = dword ptr -4
.text:00401020 arg_0           = dword ptr  8
.text:00401020 arg_4           = dword ptr  0Ch
.text:00401020
.text:00401020                 push    ebp
.text:00401021                 mov     ebp, esp
.text:00401023                 sub     esp, 48h
.text:00401026                 push    ebx
.text:00401027                 push    esi
.text:00401028                 push    edi
.text:00401029                 lea     edi, [ebp+var_48]
.text:0040102C                 mov     ecx, 12h
.text:00401031                 mov     eax, 0CCCCCCCCh
.text:00401036                 rep stosd
.text:00401038                 mov     eax, [ebp+arg_0]
.text:0040103B                 imul    eax, [ebp+arg_4]
.text:0040103F                 mov     [ebp+var_8], eax
.text:00401042                 mov     eax, [ebp+var_8]
.text:00401045                 mov     edx, [ebp+var_4]
.text:00401048                 pop     edi
.text:00401049                 pop     esi
.text:0040104A                 pop     ebx
.text:0040104B                 mov     esp, ebp
.text:0040104D                 pop     ebp
.text:0040104E                 retn
.text:0040104E add             endp
.text:0040104E
.text:0040104E ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:0040104F                 dd 4 dup(0CCCCCCCCh)
.text:0040105F                 align 10h
.text:00401060
.text:00401060 ; 圹圹圹圹圹圹圹?S U B R O U T I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?
.text:00401060
.text:00401060 ; Attributes: bp-based frame
.text:00401060
.text:00401060 main            proc near               ; CODE XREF: j_mainj
.text:00401060
.text:00401060 var_50          = dword ptr -50h
.text:00401060 var_10          = dword ptr -10h
.text:00401060 var_C           = dword ptr -0Ch
.text:00401060 var_8           = dword ptr -8
.text:00401060 var_4           = dword ptr -4
.text:00401060
.text:00401060                 push    ebp
.text:00401061                 mov     ebp, esp
.text:00401063                 sub     esp, 50h
.text:00401066                 push    ebx
.text:00401067                 push    esi
.text:00401068                 push    edi
.text:00401069                 lea     edi, [ebp+var_50]
.text:0040106C                 mov     ecx, 14h
.text:00401071                 mov     eax, 0CCCCCCCCh
.text:00401076                 rep stosd
.text:00401078                 push    4
.text:0040107A                 push    3
.text:0040107C                 call    j_add
.text:00401081                 add     esp, 8
.text:00401084                 mov     [ebp+var_10], eax
.text:00401087                 mov     [ebp+var_C], edx
.text:0040108A                 mov     eax, [ebp+var_10]
.text:0040108D                 mov     [ebp+var_8], eax
.text:00401090                 mov     ecx, [ebp+var_C]
.text:00401093                 mov     [ebp+var_4], ecx
.text:00401096                 mov     edx, [ebp+var_8]
.text:00401099                 push    edx
.text:0040109A                 push    offset ??_C@_0L@CMGB@t?4a?5?$DN?5?$CFld?6?$AA@ ; "t.a = %ld\n"
.text:0040109F                 call    printf
.text:004010A4                 add     esp, 8
.text:004010A7                 xor     eax, eax
.text:004010A9                 pop     edi
.text:004010AA                 pop     esi
.text:004010AB                 pop     ebx
.text:004010AC                 add     esp, 50h
.text:004010AF                 cmp     ebp, esp
.text:004010B1                 call    __chkesp
.text:004010B6                 mov     esp, ebp
.text:004010B8                 pop     ebp
.text:004010B9                 retn
.text:004010B9 main            endp

 

    下面是实现方式的栈示意图:

    

 

    总结:

    (1.1)用 edx:eax 传递返回值。调用方不需要在栈上向 add 函数传递接受返回值的地址。

    (2.2)debug 版本在调用方生成临时对象返回值,然后再把临时对象拷贝到 main 临时变量所在地址。效率低。

 

    (2)release 版本,汇编代码如下:

 

small_struct_release
.text:00401000 sub_401000      proc near               ; CODE XREF: sub_401020+7p
.text:00401000
.text:00401000 var_4           = dword ptr -4
.text:00401000 arg_0           = dword ptr  4
.text:00401000 arg_4           = dword ptr  8
.text:00401000
.text:00401000                 mov     eax, [esp+arg_0] ; add 函数
.text:00401004                 mov     edx, [esp+var_4]
.text:00401008                 sub     esp, 8
.text:0040100B                 imul    eax, [esp+8+arg_4]
.text:00401010                 add     esp, 8
.text:00401013                 retn
.text:00401013 sub_401000      endp
.text:00401013
.text:00401013 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:00401014                 align 10h
.text:00401020
.text:00401020 ; 圹圹圹圹圹圹圹?S U B R O U T I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?
.text:00401020
.text:00401020
.text:00401020 sub_401020      proc near               ; CODE XREF: start+AFp
.text:00401020
.text:00401020 var_4           = dword ptr -4
.text:00401020
.text:00401020                 sub     esp, 8          ; 相当于 main 函数
.text:00401023                 push    4
.text:00401025                 push    3
.text:00401027                 call    sub_401000
.text:0040102C                 add     esp, 8
.text:0040102F                 mov     [esp+8+var_4], edx
.text:00401033                 push    eax
.text:00401034                 push    offset aT_aLd   ; "t.a = %ld\n"
.text:00401039                 call    sub_401050
.text:0040103E                 xor     eax, eax
.text:00401040                 add     esp, 10h
.text:00401043                 retn
.text:00401043 sub_401020      endp

 

    总结:

    (2.1)同(1.1),用 edx:eax 传递返回值,不需要传递接收返回值的地址。

    (2.2)release 版本调用方没有临时对象,效率基本等同于传结构体指针。

    (2.3)release 版本优化的太厉害,甚至都没有把返回值完整的拷贝到临时变量 t (只拷贝了结构体中的成员t.b,t.a 的拷贝被认为没有存在价值而被优化掉了,因为 t.a 的值存于 eax),和高级语言有较大差别。

 

    (二)超过 8 bytes 的结构体,调用方需要提供用于接收返回值的地址。

    如果是超过 8 bytes 的结构体,EDX:EAX 将容纳不下,这时就需要调用方提供接受返回值的地址,即调用方在栈上分配临时对象,并把其地址通过栈传递给函数(先 push 参数,最后 push 用于设置返回值的结构体地址)。

    把上述代码中的结构体定义增加一个 int 成员即可令结构体超过 8 bytes,即调整上述代码的 struct 定义:

    struct A
    {
       int a;
       int b;
       int c;
    };

 

    使用 VC6 编译后产生的汇编代码如下:

    debug 版本:

large_struct_debug
.text:00401020 add             proc near               ; CODE XREF: j_addj
.text:00401020
.text:00401020 var_4C          = dword ptr -4Ch
.text:00401020 var_C           = dword ptr -0Ch
.text:00401020 var_8           = dword ptr -8
.text:00401020 var_4           = dword ptr -4
.text:00401020 arg_0           = dword ptr  8
.text:00401020 arg_4           = dword ptr  0Ch
.text:00401020 arg_8           = dword ptr  10h
.text:00401020
.text:00401020                 push    ebp
.text:00401021                 mov     ebp, esp
.text:00401023                 sub     esp, 4Ch
.text:00401026                 push    ebx
.text:00401027                 push    esi
.text:00401028                 push    edi
.text:00401029                 lea     edi, [ebp+var_4C]
.text:0040102C                 mov     ecx, 13h
.text:00401031                 mov     eax, 0CCCCCCCCh
.text:00401036                 rep stosd
.text:00401038                 mov     eax, [ebp+arg_4]
.text:0040103B                 imul    eax, [ebp+arg_8]
.text:0040103F                 mov     [ebp+var_C], eax
.text:00401042                 mov     ecx, [ebp+arg_0]
.text:00401045                 mov     edx, [ebp+var_C]
.text:00401048                 mov     [ecx], edx
.text:0040104A                 mov     eax, [ebp+var_8]
.text:0040104D                 mov     [ecx+4], eax
.text:00401050                 mov     edx, [ebp+var_4]
.text:00401053                 mov     [ecx+8], edx
.text:00401056                 mov     eax, [ebp+arg_0]
.text:00401059                 pop     edi
.text:0040105A                 pop     esi
.text:0040105B                 pop     ebx
.text:0040105C                 mov     esp, ebp
.text:0040105E                 pop     ebp
.text:0040105F                 retn
.text:0040105F add             endp
.text:0040105F
.text:00401060
.text:00401060 ; 圹圹圹圹圹圹圹?S U B R O U T I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?
.text:00401060
.text:00401060 ; Attributes: bp-based frame
.text:00401060
.text:00401060 main            proc near               ; CODE XREF: j_mainj
.text:00401060
.text:00401060 var_64          = dword ptr -64h
.text:00401060 var_24          = dword ptr -24h
.text:00401060 var_18          = dword ptr -18h
.text:00401060 var_14          = dword ptr -14h
.text:00401060 var_10          = dword ptr -10h
.text:00401060 var_C           = dword ptr -0Ch
.text:00401060 var_8           = dword ptr -8
.text:00401060 var_4           = dword ptr -4
.text:00401060
.text:00401060                 push    ebp
.text:00401061                 mov     ebp, esp
.text:00401063                 sub     esp, 64h
.text:00401066                 push    ebx
.text:00401067                 push    esi
.text:00401068                 push    edi
.text:00401069                 lea     edi, [ebp+var_64]
.text:0040106C                 mov     ecx, 19h
.text:00401071                 mov     eax, 0CCCCCCCCh
.text:00401076                 rep stosd
.text:00401078                 push    4
.text:0040107A                 push    3
.text:0040107C                 lea     eax, [ebp+var_24]
.text:0040107F                 push    eax
.text:00401080                 call    j_add
.text:00401085                 add     esp, 0Ch
.text:00401088                 mov     ecx, [eax]
.text:0040108A                 mov     [ebp+var_18], ecx
.text:0040108D                 mov     edx, [eax+4]
.text:00401090                 mov     [ebp+var_14], edx
.text:00401093                 mov     eax, [eax+8]
.text:00401096                 mov     [ebp+var_10], eax
.text:00401099                 mov     ecx, [ebp+var_18]
.text:0040109C                 mov     [ebp+var_C], ecx
.text:0040109F                 mov     edx, [ebp+var_14]
.text:004010A2                 mov     [ebp+var_8], edx
.text:004010A5                 mov     eax, [ebp+var_10]
.text:004010A8                 mov     [ebp+var_4], eax
.text:004010AB                 mov     ecx, [ebp+var_C]
.text:004010AE                 push    ecx
.text:004010AF                 push    offset ??_C@_0L@CMGB@t?4a?5?$DN?5?$CFld?6?$AA@ ; "t.a = %ld\n"
.text:004010B4                 call    printf
.text:004010B9                 add     esp, 8
.text:004010BC                 xor     eax, eax
.text:004010BE                 pop     edi
.text:004010BF                 pop     esi
.text:004010C0                 pop     ebx
.text:004010C1                 add     esp, 64h
.text:004010C4                 cmp     ebp, esp
.text:004010C6                 call    __chkesp
.text:004010CB                 mov     esp, ebp
.text:004010CD                 pop     ebp
.text:004010CE                 retn
.text:004010CE main            endp

 

    release 版本:

large_struct_release
.text:00401000 sub_401000      proc near               ; CODE XREF: sub_401030+Cp
.text:00401000
.text:00401000 var_8           = dword ptr -8
.text:00401000 var_4           = dword ptr -4
.text:00401000 arg_0           = dword ptr  4
.text:00401000 arg_4           = dword ptr  8
.text:00401000 arg_8           = dword ptr  0Ch
.text:00401000
.text:00401000                 mov     ecx, [esp+arg_4]
.text:00401004                 mov     eax, [esp+arg_0]
.text:00401008                 sub     esp, 0Ch
.text:0040100B                 imul    ecx, [esp+0Ch+arg_8]
.text:00401010                 mov     edx, eax
.text:00401012                 mov     [edx], ecx
.text:00401014                 mov     ecx, [esp+0Ch+var_8]
.text:00401018                 mov     [edx+4], ecx
.text:0040101B                 mov     ecx, [esp+0Ch+var_4]
.text:0040101F                 mov     [edx+8], ecx
.text:00401022                 add     esp, 0Ch
.text:00401025                 retn
.text:00401025 sub_401000      endp
.text:00401025
.text:00401025 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.text:00401026                 align 10h
.text:00401030
.text:00401030 ; 圹圹圹圹圹圹圹?S U B R O U T I N E 圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹?
.text:00401030
.text:00401030
.text:00401030 sub_401030      proc near               ; CODE XREF: start+AFp
.text:00401030
.text:00401030 var_14          = dword ptr -14h
.text:00401030 var_10          = dword ptr -10h
.text:00401030 var_C           = dword ptr -0Ch
.text:00401030
.text:00401030                 sub     esp, 18h
.text:00401033                 push    4
.text:00401035                 lea     eax, [esp+1Ch+var_C]
.text:00401039                 push    3
.text:0040103B                 push    eax
.text:0040103C                 call    sub_401000
.text:00401041                 mov     ecx, eax
.text:00401043                 add     esp, 0Ch
.text:00401046                 mov     eax, [ecx]
.text:00401048                 push    eax
.text:00401049                 push    offset aT_aLd   ; "t.a = %ld\n"
.text:0040104E                 mov     edx, [ecx+4]
.text:00401051                 mov     [esp+20h+var_14], edx
.text:00401055                 mov     ecx, [ecx+8]
.text:00401058                 mov     [esp+20h+var_10], ecx
.text:0040105C                 call    sub_401070
.text:00401061                 xor     eax, eax
.text:00401063                 add     esp, 20h
.text:00401066                 retn
.text:00401066 sub_401030      endp

 

    上述两种编译结果,实现的模型基本相同。因此在这里以debug版本代码为主,一并分析,其栈示意图如下,下图左侧为 debug 版本,右侧是 release 版本:

 

    

 

    总结:

    (1)当结构体超过 8 bytes,不能用 EDX:EAX 传递,这时调用方在栈上保留有一个用于填充返回值的结构体,其地址在入栈参数后 push 到栈上。函数将会根据这个地址,把返回值设置到这个地址。

    (2)在 main 函数中,debug 版本比 release 版本还多了一个临时对象,效率低。而 release 版本中只有返回值和临时变量 t,效率略高于 debug。但两者模型基本一致,总体效率低于传结构体指针。

    (3)release 版本同样优化比较厉害,main 函数中对 t 的赋值是不完整的,因为编译器认为没有必要,只要满足代码等效即可。

 

    最后我们总结针对较大结构体(超过 8 bytes)时,返回结构体的函数的实现方式的基本模型:

 

    (1)调用方在栈上分配用于接收返回值的临时结构体,并把地址通过栈传递给函数。

    (2)函数根据返回值的地址,设置返回值。

    (3)调用方根据需要,把返回值再赋值给需要的临时变量。

    (4)返回时,eax 存储的是返回值的那个地址。

 

    因此,从上面的过程可以看到,由于存在临时对象和拷贝操作,其效率比传递结构体指针的函数低。

 

    由于不管 debug 还是 release,对于“大结构体”都会在栈上传递返回值的地址,所以我们可以通过下面的代码,来测试出这样的结论:函数 add 的返回值(临时结构体)的地址和 main 中的变量 t 的地址是不同的。原理是,第一个形参的栈顶方向的相邻元素就是返回值的地址,因此用一个指针指向第一个形参,然后向栈顶移动一格,取出其值,就是返回值的地址。

 

#include <stdio.h>struct A
{int a;int b;int c;
};struct A add(int x, int y)
{struct A t;int* p = &x;p--;printf("address of return struct: %08X\n", *p);t.a = x * y;return t;
}int main(int argc, char* argv[])
{struct A t = add(3, 4);struct A *p1 = &t;printf("address of t in main: %p\n", &t);return 0;
}

 

    上面的代码中,有一点需要注意,返回值的地址和 t 的地址的关系是依赖编译器的,也就是说,没有任何保证,两者之间是否相邻以及它们之间的大小关系。但你可以通过尝试移动上面的指针 p1,试图将 p1 指向返回值,但这并不是一个简单容易的事情(因为编译器的行为效果是尽量避免让这个返回值被其他指针指到)。

    

 

转载于:https://www.cnblogs.com/hoodlum1980/archive/2012/07/18/2598185.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/422318.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无法确定当前的订阅失效日期_元器件失效率与失效分布

在汽车电子进行可靠性计算时&#xff0c;首先需要分析各个元器件的失效率与失效分布。元器件真实的失效率与失效分布应该是基于大量的实际数据统计得到的&#xff0c;但由于汽车电子没有专门的失效数据库&#xff0c;通常采用的是预估失效率的方法。目前业界公认的可以参考的标…

易邮服务器com组件注册失败,com组件注册失败有什么办法可以解决

COM组件实际上是系统内一些比较小的二进制可执行程序&#xff0c;它们能为应用程序&#xff0c;操作系统以及其他组件提供一定的服务。所以注册COM组件是一个重要的事情&#xff0c;但这同时也是win7系统的一个硬伤&#xff0c;win7系统注册COM组件总是失败&#xff0c;让人烦心…

前端学习(508):水平和垂直居中第一种方式

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>居中布局一</title><style>.parent{wid…

修改无效_解决docker部署gitlab时,clone地址无效和修改默认端口

部署&#xff1a;docker run -d -p 444:443 -p 88:88 -p 222:22 --name gitlab --restart always -v /usr/local/docker/gitlab/config:/etc/gitlab -v /usr/local/docker/gitlab/logs:/var/log/gitlab -v /usr/local/docker/gitlab/data:/var/opt/gitlab gitlab/gitlab-cevim …

如何实现服务器转发客户端消息,socket 怎么实现服务器与客户端不停的互发消息呢?...

在 java Socket应用的 3-4节 我把老师的代码修改了一下可以手动输入文字让对面的服务器/客户端接受&#xff0c;下面是代码&#xff1a;//客户端package 通讯;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStrea…

前端学习(509):水平和垂直居中第二种方式

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>居中布局一</title><style>.parent{wid…

pg高性能服务器,Pgpool-II 负载均衡对PG的性能影响

Pgpool-II相当于中间件&#xff0c;Pgpool-II与PG是解耦合的&#xff0c;基于这样的机制&#xff0c;Pgpool-II可以搭建在已经存在的任意版本的PG主从结构上&#xff0c;主从结构的实现与Pgpool-II无关&#xff0c;可以通过slony等工具或者PG自身的流复制机制实现。一、拓扑结构…

股上涨和下跌天数比_面对下跌,如何信心十足地逢低买入?

大众总是错的&#xff0c;对吗?也许大部分时间都是这样。但在股市“逢低买进”的想法&#xff0c;可能是金融市场中群策群力的一个罕见例子。这是一个有大量学术支持的老想法。但这并不是说股票市场总是在上涨&#xff0c;事实上&#xff0c;当下跌来临的时候&#xff0c;它们…

前端学习(511):两列布局的第一种方式

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>两列布局</title><style>.left{width: …

5g存储服务器是什么项目,5G时代对服务器有什么要求?

5G是什么?5G,其中字母G代表generation(代、际)。即第五代移动电话行动通信标准&#xff0c;也称第五代移动通信技术。5G的应用范围很广&#xff0c;大致可以包括以下几个方面&#xff1a;1、5G综合产业链分析2、5G与物联网3、5G与车联网4、5G与无线医疗5G对服务器的要求“云端…

压缩命令_Linux gzip命令:压缩文件或目录

gzip 是 Linux 系统中经常用来对文件进行压缩和解压缩的命令,通过此命令压缩得到的新文件,其扩展名通常标记为“.gz”。 再强调一下,gzip 命令只能用来压缩文件,不能压缩目录,即便指定了目录,也只能压缩目录内的所有文件。 gzip 命令的基本格式如下: [root@localhost ~]…

前端学习(512):两列布局的第一种方式的优缺点

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>两列布局</title><style>.left{width: …

svn服务器如何扫描文件,基于文件仓库进行建模协作(EA+SVN)

在文章《协同建模&版本管理(基于EA)》一文中&#xff0c;我们提到EA有四种协同建模方式&#xff1a;基于本地文件基本共享文件仓库基于模型数据库基于云服务今天我们主要介绍一下第二种方式 基于共享文件仓库进行建模协作。这种方式主要是对EA中各个模型包应用版本控制来实…

获取本地 qt_用QT实现视频/音乐播放组件

前言我已经有四五天没有发布文章了&#xff0c;趁着这个周末有空&#xff0c;就又开始构思我们自己的QT组件库中的新组件&#xff0c;思考还有哪些有用、有趣、值得研究学习并构建实现的组件&#xff0c;于是又有了两个新的目标&#xff0c;即多媒体播放组件和地图组件。之所以…

c++文件读写

http://stlchina.huhoo.net/bin/view.pl/Main/STLDetailString 添加#include <fstream> using namespace std; View Code 1 //ofstream myfile("c:\\1.txt",ios::out|ios::trunc);2 //3 //myfile<<"中国国国" << endl<< "网…

谁在窥屏_TheShy直播被窥屏搞怕了,为了防止被窥屏,这个做法绝了

前言&#xff1a;英雄联盟LPL赛区已经发展了十年&#xff0c;请你大胆试想下&#xff0c;如果终有一天英雄联盟会被其他游戏所淹没替代&#xff0c;让你选出自己心目中最强的游戏玩家&#xff0c;你的脑海里首先浮现的是谁的身影呢&#xff1f;笔者的脑海里首先是TheShy。TheSh…

前端学习(516):两列布局的第三种解决方案

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>第三种实现方案</title><style>.parent…

qchart 设置线颜色_实战PyQt5: 137-QChart图表之散点图

散点图(scatter chart)将序列显示为一组点。值由点在图表中的位置表示。类别由图表中的不同标记表示。散点图通常用于比较跨类别的聚合数据。在QChart中&#xff0c;使用类QScatterSeries创建散点图。QScatterSeriesQScatterSeries类在散点图中显示数据。散点数据在图表上显示为…