当前位置: 首页 > 编程日记 > 正文

关于Linux静态库和动态库的分析

From:

http://hi.baidu.com/bdccutysj/blog/item/5bae7f0202abac7c3912bb15.html

1.什么是库
在windows平台和linux平台下都大量存在着库。
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。
由于windows和linux的本质不同,因此二者库的二进制是不兼容的。
本文仅限于介绍linux下的库。


2.库的种类
linux下的库有两种:静态库和共享库(动态库)。
二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。


3.库存在的意义
库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。
共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。


4.库文件是如何产生的在linux下
静态库的后缀是.a,它的产生分两步
Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step 2.ar命令将很多.o转换成.a,成文静态库
动态库的后缀是.so,它由gcc加特定参数编译产生。
例如:
$ gcc -fPIC -c *.c $ gcc -shared -Wl,-soname, libfoo.so.1 -o libfoo.so.1.0 *.


5.库文件是如何命名的,有没有什么规范
在linux下,库文件一般放在/usr/lib /lib下,
静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称
动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号, minor是副版本号


6.如何知道一个可执行程序依赖哪些库
ldd命令可以查看一个可执行程序依赖的共享库,
例如# ldd /bin/lnlibc.so.6
=> /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2
=> /lib/ld- linux.so.2 (0×40000000)
可以看到ln命令依赖于libc库和ld-linux库


7.可执行程序在执行的时候如何定位共享库文件
当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径
此时就需要系统动态载入器(dynamic linker/loader)
对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的 DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib目录找到库文件后将其载入内存


8.在新安装一个库之后如何让系统能够找到他
如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。
如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下
1.编辑/etc/ld.so.conf文件,加入库文件所在目录的路径
2.运行ldconfig,该命令会重建/etc/ld.so.cache文件


我 们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静 态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。本文主要通过举例来说明在Linux 中如何创建静态库和动态库,以及使用它们。在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。

第1步:编辑得到举例的程序--hello.h、hello.c和main.c;

hello.h(见程序1)为该函数库的头文件。

hello.c(见程序2)是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出"Hello XXX!"。

main.c(见程序3)为测试库文件的主程序,在主程序中调用了公用函数hello。


程序1: hello.h

#ifndef HELLO_H
#define HELLO_H

void hello(const char *name);

#endif //HELLO_H


程序2: hello.c


#include <stdio.h>

void hello(const char *name)
{
printf("Hello %s!\n", name);
}



程序3: main.c
#include "hello.h"

int main()
{
hello("everyone");
return 0;
}


第2步:将hello.c编译成.o文件;

无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过gcc先编译成.o文件。

在系统提示符下键入以下命令得到hello.o文件。

# gcc -c hello.c

#

(注1:本文不介绍各命令使用和其参数功能,若希望详细了解它们,请参考其他文档。)

(注2:首字符"#"是系统提示符,不需要键入,下文相同。)

我们运行ls命令看看是否生存了hello.o文件。

# ls

hello.c hello.h hello.o main.c

#

(注3:首字符不是"#"为系统运行结果,下文相同。)

在ls命令结果中,我们看到了hello.o文件,本步操作完成。

下面我们先来看看如何创建静态库,以及使用它。


第3步:由.o文件创建静态库;

静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,需要注意这点。创建静态库用ar命令。

在系统提示符下键入以下命令将创建静态库文件libmyhello.a。

# ar cr libmyhello.a hello.o

#

我们同样运行ls命令查看结果:

# ls

hello.c hello.h hello.o libmyhello.a main.c

#

ls命令结果中有libmyhello.a。


第4步:在程序中使用静态库;

静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件。

在程序3:main.c中,我们包含了静态库的头文件hello.h,然后在主程序main中直接调用公用函数hello。下面先生成目标程序hello,然后运行hello程序看看结果如何。

# gcc -o hello main.c -L. -lmyhello

# ./hello

Hello everyone!

#

我们删除静态库文件试试公用函数hello是否真的连接到目标文件 hello中了。

# rm libmyhello.a

rm: remove regular file `libmyhello.a'? y

# ./hello

Hello everyone!

#

程序照常运行,静态库中的公用函数已经连接到目标文件中了。

我们继续看看如何在Linux中创建动态库。我们还是从.o文件开始。


第5步:由.o文件创建动态库文件;

动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件扩展名为.so。例如:我们将创建的动态库名为myhello,则动态库文件名就是libmyhello.so。用gcc来创建动态库。

在系统提示符下键入以下命令得到动态库文件libmyhello.so。

# gcc -shared -fPCI -o libmyhello.so hello.o

#

我们照样使用ls命令看看动态库文件是否生成。

# ls

hello.c hello.h hello.o libmyhello.so main.c

#


第6步:在程序中使用动态库;

在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。我们先运行gcc命令生成目标文件,再运行它看看结果。

# gcc -o hello main.c -L. -lmyhello

# ./hello

./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

#

哦!出错 了。快看看错误提示,原来是找不到动态库文件libmyhello.so。程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件。 若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。我们将文件libmyhello.so复制到目录/usr/lib中,再试试。

# mv libmyhello.so /usr/lib

# ./hello

./hello: error while loading shared libraries: /usr/lib/libhello.so: cannot restore segment prot after reloc: Permission denied
由于SELinux引起,

# chcon -t texrel_shlib_t /usr/lib/libhello.so

# ./hello

Hello everyone!

#

成功了。这也进一步说明了动态库在程序运行时是需要的。

我们回过头看看,发现使用静态库和使用动态库编译成目标程序使用的gcc命令完全一样,那当静态库和动态库同名时,gcc命令会使用哪个库文件呢?抱着对问题必究到底的心情,来试试看。

先删除 除.c和.h外的 所有文件,恢复成我们刚刚编辑完举例程序状态。

# rm -f hello hello.o /usr/lib/libmyhello.so

# ls

hello.c hello.h main.c

#

在来创建静态库文件libmyhello.a和动态库文件libmyhello.so。

# gcc -c hello.c

# ar cr libmyhello.a hello.o

# gcc -shared -fPCI -o libmyhello.so hello.o

# ls

hello.c hello.h hello.o libmyhello.a libmyhello.so main.c

#

通过上述最后一条ls命令,可以发现静态库文件libmyhello.a和动态库文件libmyhello.so都已经生成,并都在当前目录中。然后,我们运行gcc命令来使用函数库myhello生成目标文件hello,并运行程序 hello。

# gcc -o hello main.c -L. -lmyhello

# ./hello

./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

#

从程序hello运行的结果中很容易知道,当静态库和动态库同名时, gcc命令将优先使用动态库。

基本概念

库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀。

例如:libhello.so libhello.a 为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如: libhello.so.1.0,由于程序连接默认以.so为文件后缀名。所以为了使用这些库,通常使用建立符号连接的方式。

ln -s libhello.so.1.0 libhello.so.1

ln -s libhello.so.1 libhello.so

当 要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然 而,对动态库而言,就不是这样。动态库会在执行程序内留下一个标记指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺 省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。 现在假设有一个叫hello的程序开发包,它提供一个静态库libhello.a 一个动态库libhello.so,一个头文件hello.h,头文件中提供sayhello()这个函数 /* hello.h */ void sayhello(); 另外还有一些说明文档。

这一个典型的程序开发包结构 与动态库连接 linux默认的就是与动态库连接,下面这段程序testlib.c使用hello库中的sayhello()函数

/*testlib.c*/

#include <>

#include <>

int main()

{

sayhello();

return 0;

}

使用如下命令进行编译 $gcc -c testlib.c -o testlib.o

用如下命令连接: $gcc testlib.o -lhello -o testlib

连接时要注意,假设libhello.o 和libhello.a都在缺省的库搜索路径下/usr/lib下,如果在其它位置要加上-L参数 与与静态库连接麻烦一些,主要是参数问题。还是上面的例子:

$gcc testlib.o -o testlib -WI,-Bstatic -lhello

注:这个特别的"-WI,-Bstatic"参数,实际上是传给了连接器ld。指示它与静态库连接,如果系统中只有静态库当然就不需要这个参数了。 如果要和多个库相连接,而每个库的连接方式不一样,比如上面的程序既要和libhello进行静态连接,又要和libbye进行动态连接,其命令应为:

$gcc testlib.o -o testlib -WI,-Bstatic -lhello -WI,-Bdynamic -lbye


2、动态库的路径问题 为了让执行程序顺利找到动态库,有三种方法:

(1)把库拷贝到/usr/lib和/lib目录下。

(2)在LD_LIBRARY_PATH环境变量中加上库所在路径。

例如动态库libhello.so在/home/ting/lib目录下,以bash为例,使用命令:

$export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ting/lib

(3) 修改/etc/ld.so.conf文件,把库所在的路径加到文件末尾,并执行ldconfig刷新。这样,加入的目录下的所有库文件都可见。


3、查看库中的符号

有时候可能需要查看一个库中到底有哪些函数,nm命令可以打印出库中的涉及到的所有符号。库既可以是静态的也可以是动态的。nm列出的符号有很多,常见的有三种:

一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;

一种是库中定义的函数,用T表示,这是最常见的;

另外一种是所谓的“弱 态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示。

例如,假设开发者希望知道上文提到的hello库中是否定义了 printf():

$nm libhello.so |grep printf U

其中printf U表示符号printf被引用,但是并没有在函数内定义,由此可以推断,要正常使用hello库,必须有其它库支持,再使用ldd命令查看hello依赖于哪些库:

$ldd hello libc.so.6=>/lib/libc.so.6(0x400la000) /lib/ld-linux.so.2=>/lib/ld-linux.so.2 (0x40000000)

从上面的结果可以继续查看printf最终在哪里被定义,有兴趣可以go on


4、生成库

第一步要把源代码编绎成目标代码。

以下面的代码为例,生成上面用到的hello库:

/* hello.c */

#include <>

void sayhello()

{

printf("hello,world ");

}

用gcc编绎该文件,在编绎时可以使用任何全法的编绎参数,例如-g加入调试代码等: gcc -c hello.c -o hello.o

(1)连接成静态库 连接成静态库使用ar命令,其实ar是archive的意思

$ar cqs libhello.a hello.o

(2)连接成动态库 生成动态库用gcc来完成,由于可能存在多个版本,因此通常指定版本号:

$gcc -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 hello.o

另外再建立两个符号连接:

$ln -s libhello.so.1.0 libhello.so.1

$ln -s libhello.so.1 libhello.so

这样一个libhello的动态连接库就生成了。最重要的是传gcc -shared 参数使其生成是动态库而不是普通执行程序。 -Wl 表示后面的参数也就是-soname,libhello.so.1直接传给连接器ld进行处理。实 际上,每一个库都有一个soname,当连接器发现它正在查找的程序库中有这样一个名称,连接器便会将soname嵌入连结中的二进制文件内,而不是它正 在运行的实际文件名,在程序执行期间,程序会查找拥有 soname名字的文件,而不是库的文件名,换句话说,soname是库的区分标志。 这样做的目的主要是允许系统中多个版本的库文件共存,习惯上在命名库文件的时候通常与soname相同 libxxxx.so.major.minor 其中,xxxx是库的名字,major是主版本号,minor 是次版本号

相关文章:

求解|x-y|最小

问题&#xff1a;输入数组a和b&#xff0c;请通过交换的方式重新分配两个数组&#xff0c;使得|a-b|最小 提供一种思路&#xff1a; 当前数组a和数组b的和之差为 A sum(a) - sum(b) a的第i个元素和b的第j个元素交换后&#xff0c;a和b的和之差为 A ( sum(a) - a[i] b…

最老程序员创业札记:全文检索、数据挖掘、推荐引擎应用50

广告客户吴言之前也研究过互联网广告业务模式&#xff0c;具体来讲可以分为六大模式&#xff1a;门户网站广告模式、搜索引擎广告模式、社会化网站广告模式、视频网站广告模式、植入式广告模式、广告联盟模式。对于门户网站广告模式来讲&#xff0c;这是一种push模式&#xff0…

终于遇见——王阳明

一个厉害的人 王阳明&#xff0c;五百年来的一个圣人&#xff0c;最后总结了四句教&#xff1a;无善无恶心之本&#xff0c;有善有恶意之动&#xff0c;知善知恶是良知&#xff0c;为善去恶是格物。看完王阳明的一生&#xff0c;再看到这四句话时&#xff0c;直让人发怔&#x…

【jquery】jquery基础知识

总体介绍&#xff1a; jquery是一个js的类库&#xff0c;为了减少代码量实现更多的功能 1、jquery使用需要引入jquery的类库&#xff0c;其中有一名称带min&#xff08;产品版&#xff09;有一个不带min的&#xff08;开发版&#xff09;&#xff0c;作用相同。当我们同网页打…

针对19端口的Chargen进行Dos***

先普及一下基础吧&#xff1a; 英语全名&#xff1a;Character Generator Protocol 汉语&#xff1a;字符发生器协议 默认端口&#xff1a;TCP 19&#xff0c;UDP 19 本协议在RFC 864中定义。 在TCP连接建立后&#xff0c;服务器不断传送任意的字符到客户端&#xff0c;直到客户…

TCP/IP 简介

原文&#xff1a;TCP/IP 简介 第一节&#xff1a;TCP/IP 简介 第二节&#xff1a;TCP/IP 寻址 第三节&#xff1a;TCP/IP 协议 第四节&#xff1a;TCP/IP 邮件 TCP/IP 是用于因特网 (Internet) 的通信协议。 计算机通信协议 计算机通信协议是对那些计算机必须遵守以便彼此通信的…

MyEclipse提示键配置、提示快捷键、提示背景色、关键字颜色、代码显示

1、提示键配置一般默认情况下&#xff0c;Eclipse &#xff0c;MyEclipse 的代码提示功能是比Microsoft Visual Studio的差很多的&#xff0c;主要是Eclipse &#xff0c;MyEclipse本身有很多选项是默认关闭的&#xff0c;要开发者自己去手动配置。如果开发者不清楚的话&#x…

【jquery】用jsp写jquery的模板

代码实现&#xff1a; <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dt…

《网页设计创意书》读后感

刚刚收到《网页设计创意书》&#xff0c;确实有点惊喜&#xff0c;开始以为是像之前审读的书一样是一叠叠的打印纸&#xff0c;没想到是一本成品书&#xff0c;拿到手上沉甸甸的&#xff0c;随便翻看了一下&#xff0c;没想到里面竟然还是全彩页印刷的&#xff0c;本书的第一感…

博客园的博客积分与排名查看方法

我是今天才知道&#xff0c;out。因为这东东默认是不显示的&#xff0c;因此找不到。 注意&#xff1a;只是你在博客园的博客的积分排名&#xff0c;而不是你的在博客园的排名。 设置-博客设置&#xff08;博客后台管理&#xff09;-选项-积分与排名打勾。刷新你的博客页面即可…

产品经理之我见

产品经理的定义&#xff1a; 1、 管理、营销自己特定产品线、品牌和服务的责任。 2、 又叫品牌经理&#xff0c;行业经理&#xff0c;顾客细分经理等。 产品经理存在的地方 1、 消费型的零售业&#xff0c;服务业&#xff08;化妆品&#xff0c;金融行业等&#xff09;。 2、…

casperjs 安装试用

纠结了好久&#xff0c;一直报错, 具体错误信息现在已经忘了&#xff0c;后来看了官网的prerequisite&#xff0c;才知道要安装特定版本或greater 的 phantomjs 和 Python。我这边主要是没装python。当然还有casperjs 的bin 路径也要加到环境变量里&#xff08;windows). 然后都…

【jquery】jquery选择器

知识点 1、jquery选择器的作用是选择jquery页面中的html元素。 2、常用的选择器有&#xff1a;基本选择器、层级选择器、过滤选择器、属性选择器。 基本选择器 1、 id 选择器 代码实现&#xff1a; element $("#id") 等价于 document.getElementById("…

android-轻松监听来电和去电

要监听android打电话和接电话&#xff0c;只需下面2步骤 1.第一步&#xff0c;写一个Receiver继承自BroadcastReceiver public class PhoneStatReceiver extends BroadcastReceiver{private static final String TAG "PhoneStatReceiver";// private stat…

【sql】实现分页查询

分页查询&#xff0c;以五条五条查询为例&#xff1a; 代码实现&#xff1a; select * from goods_list LIMIT 0 , 5; 从第0条开始&#xff0c;查询五条

N-Case 律师事务所管理系统安装与卸载说明

目 录 1 解压安装包... 1 2 安装系统... 1 3 登录系统... 2 4 安装失败... 3 5 系统试用帐号... 3 6 远程访问... 3 7 卸载系统... 3 1 解压安装包 先解压软件包&#xff0c;解压后把redcat目录剪切或拷贝到D盘根目录下即可。一定要放到D…

jmeter分析性能报告时的误区

概述 我们用jmeter做性能测试&#xff0c;必然需要学会分析测试报告。但是初学者常常因为对概念的不清晰&#xff0c;最后被测试报告带到沟里去。 常见的误区 分析响应时间全用平均值响应时间不和吞吐量挂钩响应时间和吞吐量不和成功率挂钩。。。。。 平均值特别不靠谱 平均值为…

const的位置

2019独角兽企业重金招聘Python工程师标准>>> 1.指向常量的指针 const 类型 * 指针名 或者 类型 const * 指针名特点&#xff1a;不能修改指向的对象的值,可以修改指针的指向int var11; const int var22; const int * p1&var1; const int * p2&var2; *p1100;…

zookeeper入门系列 : 分布式事务

上一章我们了解了zookeeper到底是什么&#xff0c;这一章重点来看zookeeper当初到底面临什么问题&#xff1f;而zookeeper又是如何解决这些问题的&#xff1f; 实际上zookeeper主要就是解决分布式环境下的一致性问题。那么解决这个问题到底有哪些难点呢&#xff1f;我们一步一步…

rdlc报表显示条码 .

1.条码的生成&#xff1a; private Bitmap GetCode39(string strSource) { int x 5; //左邊界 int y 0; //上邊界 int WidLength 2; //粗BarCode長度 int NarrowLength 1; //細BarCode長度 …

python列表(数组)

python列表&#xff08;数组&#xff09; 列表&#xff08;list&#xff09; 就是 数组 - 列表是Python中的一个对象 - 对象&#xff08;object&#xff09;就是内存中专门用来存储数据的一块区域 - 之前我们学习的对象&#xff0c;像数值&#xff0c;它只能保存一…

【js】common.jsp的使用

通过将引入common.jsp将所有文件都需要的内容或静态资源引入&#xff0c;相当于一个页面&#xff0c;在页面被编译之前合并。 代码实现 <% include file "common.jsp的相对路径"%> 注意&#xff1a; <% page language"java" contentType&quo…

12th,Jan 研究生创新项目申报成功

今天的好消息是研究生创新项目申报成了&#xff0c;省里拨下来是1.8k&#xff0c;本来学校应该配3.6k&#xff0c;但是按照以往的经验&#xff0c;学校那3.6k是不会给的。。。所以总共就1.8k&#xff0c;呵呵&#xff0c;钱虽然不多&#xff0c;但是也是个小小小的成就吧。 昨晚…

Android studio中2种build.gradle文件介绍

根目录下的build.gradle通常不需要修改这个文件中的内容&#xff0c;除非需要添加一些全局的项目构建配置 buildscript {repositories {google() //声明代码托管仓库Googlejcenter() //声明代码托管仓库&#xff0c;用于引用jcenter上的开源项目}dependencies {classpath …

10个有趣的javascript和css库(2019年5月最新)

我们的使命是让您了解最新和最酷的Web开发趋势。这就是为什么我们每个月都会发布一些精选的资源&#xff0c;这些资源是我们偶然发现并认为值得您关注的。 1.Tessaract.js 强大的javascript&#xff08;节点和浏览器&#xff09;库&#xff0c;用于从图像中提取文本。它能自动检…

快速开发rails、==常用插件==

1、简化css编写的&#xff1a;sass http://sass-lang.com/download.html 2、简化html编写的:haml http://haml-lang.com/转载于:https://www.cnblogs.com/klobohyz/archive/2011/10/31/2230080.html

【js】绑定事件的两种方法

方法一&#xff1a; 为需要绑定事件的标签添加一个属性onclick 代码实现&#xff1a; <input type"button" value"测试按钮" onclick"testClick()" /> 方法二&#xff1a; 用jquery方法绑定事件 代码实现&#xff1a; <input id&…

对于学习方式的一些思考

再牛X的书都不要太当回事儿&#xff0c;书只是知识的一个载体&#xff0c;掌握知识的途径之一。学习的过程应该是由一个个知识模块所驱动的&#xff0c;继而去调动身边的学习资源和工具&#xff0c;而不是被一本本所谓的牛书生拉硬拽着去学一大套可能永远都用不到的东西。“知识…

python开发环境安装

PyCharm的安装地址&#xff1a;http://www.jetbrains.com/pycharm/download/#sectionwindows&#xff0c;免费的可以选择社区版本 Python解释器的安装地址&#xff1a;https://www.python.org/downloads/&#xff0c;选择对应的平台及版本下载&#xff0c;安装时勾选 添加到环…

HGOI 20190709 题解

Problem A 紫色激情 一个序列$\{a_n\}$&#xff0c;求出方差最大的子序列。 其中方差 [l,r] 的定义是$S^2 \frac{1}{n} \sum\limits_{il}^{r} (x_i-\bar{x})^2$ 对于100%的数据满足$n \leq 10^3$ Sol : 直接推一波公式就可以前缀和优化了。 ${ S_{l,r} }^2 -\bar{x}^2 \frac{…