精华内容
下载资源
问答
  • nsymbol = 1e6%每种信噪比下符号数的发送符号数 data = randint(1,nsymbol,[0,1]%产生1行nsymbol列均匀分布的随机数0,1 bpsk_mod = 2*data-1%调制0转化为-11转化为1 spow = norm(bpsk_mod^2/nsymbol%求每个符号的...
  • 主要还是为了调试方便,虽然理论上使用命令行方式生成库也能调试,详见:GDAL库调试(包括跨语言调试),但是我把gdal库的pdb文件、ilk文件都拷贝到输出目录依然无法调试,使用windbg进行调试,感觉繁琐了点,还有...

    作者:朱金灿

    来源:http://blog.csdn.net/clever101

     

          为什么要用VS工程的方式来编译gdal库?主要还是为了调试方便,虽然理论上使用命令行方式生成库也能调试,详见:GDAL库调试(包括跨语言调试),但是我把gdal库的pdb文件、ilk文件都拷贝到输出目录依然无法调试,使用windbg进行调试,感觉繁琐了点,还有开发组的其他成员还不会用windbg这玩意,于是开始折腾将gdal源码转化为VS工程。

     

           结果一折腾之下,发现自己仿佛掉进无穷深的坑,可能就是俗称的dll地狱吧,终于在今天折腾完。下面就详细说说这一过程:

     

           第一步:使用makegdal_gen.bat生成一个VS2008工程makegdal90.vcproj,makegdal_gen.bat的具体用法见参考文献一,这里不作详述。可能有读者认为这样生成不是VS工程吗?实际上这并不是我想要可以调试的dll工程,而是一个Make工程,这个Make工程实际上调用的还是nmake的命令行,具体看下图:


            第二步就是要把make工程转化为dll工程,转化的过程很简单,用记事本将makegdal90.vcproj打开,找到Configurations节点,具体如下:

    	<Configurations>
    		<Configuration
    			Name="Debug|Win32"
    			OutputDirectory="$(ConfigurationName)"
    			IntermediateDirectory="$(ConfigurationName)"
    			ConfigurationType="0"
    			>
    			<Tool
    				Name="VCNMakeTool"
    				BuildCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 DEBUG=1"
    				ReBuildCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 DEBUG=1 clean && nmake -f makefile.vc MSVC_VER=1400 DEBUG=1"
    				CleanCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 DEBUG=1 clean"
    				Output="gdal17.dll"
    				PreprocessorDefinitions=""
    				IncludeSearchPath=""
    				ForcedIncludes=""
    				AssemblySearchPath=""
    				ForcedUsingAssemblies=""
    				CompileAsManaged=""
    			/>
    		</Configuration>
    		<Configuration
    			Name="Release|Win32"
    			OutputDirectory="$(ConfigurationName)"
    			IntermediateDirectory="$(ConfigurationName)"
    			ConfigurationType="0"
    			>
    			<Tool
    				Name="VCNMakeTool"
    				BuildCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 && nmake -f makefile.vc MSVC_VER=1400 install"
    				ReBuildCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 clean && nmake -f makefile.vc MSVC_VER=1400 && nmake -f makefile.vc MSVC_VER=1400 install"
    				CleanCommandLine="cd $(ProjectDir) && nmake -f makefile.vc MSVC_VER=1400 clean"
    				Output="gdal17.dll"
    				PreprocessorDefinitions=""
    				IncludeSearchPath=""
    				ForcedIncludes=""
    				AssemblySearchPath=""
    				ForcedUsingAssemblies=""
    				CompileAsManaged=""
    			/>
    		</Configuration>
    	</Configurations>
    

    替换为如下内容:

    	<Configurations>
    		<Configuration
    			Name="Debug|Win32"
    			OutputDirectory="..\..\..\..\Outdir\debug"
    			IntermediateDirectory="..\..\..\..\Intdir\$(ConfigurationName)\$(ProjectName)"
    			ConfigurationType="2"
    			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
    			CharacterSet="2"
    			>
    			<Tool
    				Name="VCPreBuildEventTool"
    			/>
    			<Tool
    				Name="VCCustomBuildTool"
    			/>
    			<Tool
    				Name="VCXMLDataGeneratorTool"
    			/>
    			<Tool
    				Name="VCWebServiceProxyGeneratorTool"
    			/>
    			<Tool
    				Name="VCMIDLTool"
    			/>
    			<Tool
    				Name="VCCLCompilerTool"
    				Optimization="0"
    				AdditionalIncludeDirectories=""
    				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;GDAL_EXPORTS"
    				IgnoreStandardIncludePath="false"
    				MinimalRebuild="true"
    				BasicRuntimeChecks="3"
    				RuntimeLibrary="3"
    				UsePrecompiledHeader="0"
    				WarningLevel="3"
    				Detect64BitPortabilityProblems="true"
    				DebugInformationFormat="3"
    				DisableSpecificWarnings="4251"
    				ForcedIncludeFiles=""
    			/>
    			<Tool
    				Name="VCManagedResourceCompilerTool"
    			/>
    			<Tool
    				Name="VCResourceCompilerTool"
    			/>
    			<Tool
    				Name="VCPreLinkEventTool"
    			/>
    			<Tool
    				Name="VCLinkerTool"
    				AdditionalDependencies=""
    				OutputFile="$(OutDir)/gdal-vc9.dll"
    				LinkIncremental="2"
    				AdditionalLibraryDirectories=""
    				IgnoreAllDefaultLibraries="false"
    				IgnoreDefaultLibraryNames="msvcrt.lib"
    				ForceSymbolReferences=""
    				GenerateDebugInformation="true"
    				ProgramDatabaseFile="$(OutDir)/gdal.pdb"
    				SubSystem="1"
    				RandomizedBaseAddress="1"
    				DataExecutionPrevention="0"
    				ImportLibrary="$(OutDir)/gdal-vc9.lib"
    				TargetMachine="1"
    			/>
    			<Tool
    				Name="VCALinkTool"
    			/>
    			<Tool
    				Name="VCManifestTool"
    			/>
    			<Tool
    				Name="VCXDCMakeTool"
    			/>
    			<Tool
    				Name="VCBscMakeTool"
    			/>
    			<Tool
    				Name="VCFxCopTool"
    			/>
    			<Tool
    				Name="VCAppVerifierTool"
    			/>
    			<Tool
    				Name="VCPostBuildEventTool"
    				CommandLine=""
    			/>
    		</Configuration>
    		<Configuration
    			Name="Release|Win32"
    			OutputDirectory="..\..\..\..\outdir\release"
    			IntermediateDirectory="..\..\..\..\Intdir\$(ConfigurationName)\$(ProjectName)"
    			ConfigurationType="2"
    			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
    			CharacterSet="2"
    			>
    			<Tool
    				Name="VCPreBuildEventTool"
    			/>
    			<Tool
    				Name="VCCustomBuildTool"
    			/>
    			<Tool
    				Name="VCXMLDataGeneratorTool"
    			/>
    			<Tool
    				Name="VCWebServiceProxyGeneratorTool"
    			/>
    			<Tool
    				Name="VCMIDLTool"
    			/>
    			<Tool
    				Name="VCCLCompilerTool"
    				AdditionalIncludeDirectories=""
    				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;GDAL_EXPORTS"
    				RuntimeLibrary="2"
    				UsePrecompiledHeader="0"
    				WarningLevel="3"
    				Detect64BitPortabilityProblems="true"
    				DebugInformationFormat="0"
    				DisableSpecificWarnings="4251"
    			/>
    			<Tool
    				Name="VCManagedResourceCompilerTool"
    			/>
    			<Tool
    				Name="VCResourceCompilerTool"
    			/>
    			<Tool
    				Name="VCPreLinkEventTool"
    			/>
    			<Tool
    				Name="VCLinkerTool"
    				AdditionalDependencies=""
    				OutputFile="$(OutDir)/gdal-vc9.dll"
    				LinkIncremental="1"
    				AdditionalLibraryDirectories=""
    				IgnoreDefaultLibraryNames=""
    				ForceSymbolReferences=""
    				GenerateDebugInformation="false"
    				SubSystem="2"
    				OptimizeReferences="2"
    				EnableCOMDATFolding="2"
    				RandomizedBaseAddress="1"
    				DataExecutionPrevention="0"
    				ImportLibrary="$(OutDir)/gdal-vc8.lib"
    				TargetMachine="1"
    			/>
    			<Tool
    				Name="VCALinkTool"
    			/>
    			<Tool
    				Name="VCManifestTool"
    			/>
    			<Tool
    				Name="VCXDCMakeTool"
    			/>
    			<Tool
    				Name="VCBscMakeTool"
    			/>
    			<Tool
    				Name="VCFxCopTool"
    			/>
    			<Tool
    				Name="VCAppVerifierTool"
    			/>
    			<Tool
    				Name="VCPostBuildEventTool"
    				CommandLine=""
    			/>
    		</Configuration>
    	</Configurations>
    

    这样你就将一个make工程转化为一个win32 dll工程。

     

            第三步添加附加头文件路径、预处理器和附加库。事实上这一步最为繁琐。先说说添加头文件路径,因为gdal库涉及到众多的格式,只要你数下frmts目录以及ogr\ogrsf_frmts目录下有多少个子文件夹就可以知道gdal支持多少种栅格格式和矢量格式(我的感觉是gdal库就像一座桥梁,把众多的图形图像库联结在一起),也就是说要把这么多格式的路径都添加进头文件路径。手动添加肯定是不行的,我写了一个JS文件通过遍历文件路径进行添加。然后开始添加预处理器,预处理器的作用主要有两方面,一是控制gdal库支持哪些格式,比如添加了FRMT_gtiff预处理器表示支持geotiff格式,想知道哪些栅格格式对应哪些预处理器,请看GDALAllRegister函数源码,对于支持哪些矢量格式,比如添加SHAPE_ENABLED表示支持shp格式,想知道哪些矢量格式对应哪些预处理器,请看OGRRegisterAll函数源码,二是控制是否添加附加库,比如添加HAVE_LIBJPEG表示有额外的jpeg库。我添加了下面这些预处理器:

    HAVE_XERCES
    FRMT_ceos
    FRMT_aigrid
    FRMT_elas
    FRMT_hfa
    FRMT_gtiff
    FRMT_sdts
    FRMT_raw
    FRMT_gxf
    FRMT_ceos2
    FRMT_png
    FRMT_dted
    FRMT_mem
    FRMT_jdem
    FRMT_gif
    FRMT_envisat
    FRMT_aaigrid
    FRMT_usgsdem
    FRMT_l1b
    FRMT_vrt
    FRMT_xpm
    FRMT_bmp
    FRMT_jpeg
    SHAPELIB_DLLEXPORT
    ZIP_SUPPORT
    SHAPE_ENABLED
    TAB_ENABLED
    NTF_ENABLED
    SDTS_ENABLED
    TIGER_ENABLED
    S57_ENABLED
    DGN_ENABLED
    VRT_ENABLED
    AVCBIN_ENABLED
    REC_ENABLED
    MEM_ENABLED
    _CRT_SECURE_NO_DEPRECATE
    BUILD_AS_DLL
    USE_CPL
    HAVE_GEOS
    BIGTIFF_SUPPORT
    PROJ_STATIC
    COMPILATION_ALLOWED
    HAVE_EXPAT
    JAS_WIN_MSVC_BUILD
    USE_IN_GDAL
    OGR_ENABLED
    LIBHDF_EXPORTS
    HAVE_LIBJPEG
    HAVE_LIBZ
    HDF5CPP_USEDLL
    _HDF5USEDLL_
    BUILDING_LIBCURL
    HAVE_CURL
    

           既然gdal库支持那么多格式,是不是我们都应该把每种格式的源码都编译一遍呢?回答是否定的,理由很简单,有些格式很生僻,其数据很可能你一辈子都没见过,那你编译它做什么,因此你完全可以在工程文件里果断地将一些你不想支持的格式的源码移除掉。尽管如此,我们需要的第三方库还是很多的。下面是我们需要的第三方库一览表:

    第三方库名及版本

    备注

    Expat v2.1.0_vc9

    xml格式解析库,主要为支持kml格式提供支持。

     

     

     

    zlib v1.2.3

     

     

     

    开源压缩库,为很多第三方库提供支持。

    geos v3.3.5

     

     

    开源空间分析库

    xerces v3.1.1

     

     

    xml文件解析库

    sqlite v3071401

     

     

    开源数据库,可作为ogr库的空间数据库支持

    OpenDWG

     

     

    用于支持Autocad的dwg格式,值得注意的是OpenDWG是一个cad商业联盟为解析dwg格式而联合推出的一个解析库,其库需要购买,其源码并不公开,它并不是一个库,而是一系列库的集合,具体如下

    TD_Gs.lib

    TD_Db.lib

    TD_DbRoot.lib

    TD_Ge.lib

    TD_Root.lib

    TD_AcisBuilder.lib

    TD_Gi.lib

    TD_Alloc.lib

    TD_ExamplesCommon.lib

    TD_SpatialIndex.lib。

    libwebp v0.2.0

     

     

     

    貌似是支持一种网络图片格式webp。

    Openjpeg v2.0.0-win32-x86\lib

     

     

    用于支持jpeg200格式

    pthreads v2_9_1

     

     

    跨平台线程库

    Libkml v1.3.0

     

     

    用于支持kml格式

    Jasper v1.900.1

     

     

    用于支持Jasper格式

    Curl v7.32.0

     

     

    文件传输库,貌似为了支持GIS的WMS服务,在windows平台上需要win socket支持,具体需要ws2_32.lib、wsock32.lib、Wldap32.lib这三个库支持。

    libiconv v1.11.1

     

     

    跨平台文本编码转换库

    proj v4.8

     

     

    投影转换库

    hdfeos 2_18

     

     

    用于支持hdf格式

    hdf5 v1.8.8

     

     

     

     

     

    用于支持hdf5格式

    hdf v4.2.6

     

     

    用于支持hdf5格式

    libj2k

     

     

    用于支持jpeg2000格式,不知和openjpeg有何区别。

    jpeg v8d

     

     

    用于支持jpeg库

    minizip

     

     

    支持kml格式的附加库

    uriparser

     

     

    支持kml格式的附加库



    参考文献:

     

    1. GDAL源码剖析(二)之编译说明






    展开全文
  • C语言中将数字转化为字符串

    千次阅读 2012-08-18 19:05:10
    各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望。由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出。这也导致sprintf 比...

    在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望。由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出。这也导致sprintf 比printf 有用得多。

    sprintf 是个变参函数,定义如下:
    int sprintf( char *buffer, const char *format [, argument] ... );
    除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:
    格式化字符串上。


    printf 和sprintf 都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串。

    格式化数字字符串
    sprintf 最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf 在大多数场合可以替代
    itoa。

    如:
    //把整数123 打印成一个字符串保存在s 中。
    sprintf(s, "%d", 123); //产生"123"
    可以指定宽度,不足的左边补空格:
    sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567"
    当然也可以左对齐:
    sprintf(s, "%-8d%8d", 123, 4567); //产生:"123 4567"
    也可以按照16 进制打印:
    sprintf(s, "%8x", 4567); //小写16 进制,宽度占8 个位置,右对齐
    sprintf(s, "%-8X", 4568); //大写16 进制,宽度占8 个位置,左对齐

    这样,一个整数的16 进制字符串就很容易得到,但我们在打印16 进制内容时,通常想要一种左边补0 的等宽格式,那该怎么做呢?很简单,在表示宽度的数字前面加个0 就可以了。
    sprintf(s, "%08X", 4567); //产生:"000011D7"
    上面以”%d”进行的10 进制打印同样也可以使用这种左边补0 的方式。


    这里要注意一个符号扩展的问题:比如,假如我们想打印短整数(short)-1 的内存16 进制表示形式,在Win32 平台上,一个short 型占2 个字节,所以我们自然希望用4 个16 进制数字来打印它:
    short si = -1;
    sprintf(s, "%04X", si);
    产生“FFFFFFFF”,怎么回事?因为spritnf 是个变参函数,除了前面两个参数之外,后面的参数都不是类型安全的,函数更没有办法仅仅通过一个“%X”就能得知当初函数调用前参数压栈时被压进来的到底是个4 字节的整数还是个2 字节的短整数,所以采取了统一4 字节的处理方式,导致参数压栈时做了符号扩展,扩展成了32 位的整数-1,打印时4 个位置不够了,就把32 位整数-1 的8 位16 进制都打印出来了。

    如果你想看si 的本来面目,那么就应该让编译器做0 扩展而不是符号扩展(扩展时二进制左边补0 而不是补符号位):
    sprintf(s, "%04X", (unsigned short)si);
    就可以了。或者:
    unsigned short si = -1;
    sprintf(s, "%04X", si);


    sprintf 和printf 还可以按8 进制打印整数字符串,使用”%o”。注意8 进制和16 进制都不会打
    印出负数,都是无符号的,实际上也就是变量的内部编码的直接的16 进制或8 进制表示。

    控制浮点数打印格式
    浮点数的打印和格式控制是sprintf 的又一大常用功能,浮点数使用格式符”%f”控制,默认保
    留小数点后6 位数字,比如:
    sprintf(s, "%f", 3.1415926); //产生"3.141593"
    但有时我们希望自己控制打印的宽度和小数位数,这时就应该使用:”%m.nf”格式,其中m 表
    示打印的宽度,n 表示小数点后的位数。比如:
    sprintf(s, "%10.3f", 3.1415626); //产生:" 3.142"
    sprintf(s, "%-10.3f", 3.1415626); //产生:"3.142 "
    sprintf(s, "%.3f", 3.1415626); //不指定总宽度,产生:"3.142"

    注意一个问题,你猜
    int i = 100;
    sprintf(s, "%.2f", i);
    会打出什么东东来?“100.00”?对吗?自己试试就知道了,同时也试试下面这个:
    sprintf(s, "%.2f", (double)i);
    第一个打出来的肯定不是正确结果,原因跟前面提到的一样,参数压栈时调用者并不知道跟i相对应的格式控制符是个”%f”。而函数执行时函数本身则并不知道当年被压入栈里的是个整数,于是可怜的保存整数i 的那4 个字节就被不由分说地强行作为浮点数格式来解释了,整个乱套了。不过,如果有人有兴趣使用手工编码一个浮点数,那么倒可以使用这种方法来检验一下你手工编排的结果是否正确。

    字符/Ascii 码对照
    我们知道,在C/C++语言中,char 也是一种普通的scalable 类型,除了字长之外,它与short,
    int,long 这些类型没有本质区别,只不过被大家习惯用来表示字符和字符串而已。(或许当年该把
    这个类型叫做“byte”,然后现在就可以根据实际情况,使用byte 或short 来把char 通过typedef 定义出来,这样更合适些)于是,使用”%d”或者”%x”打印一个字符,便能得出它的10 进制或16 进制的ASCII 码;反过来,使用”%c”打印一个整数,便可以看到它所对应的ASCII 字符。以下程序段把所有可见字符的ASCII 码对照表打印到屏幕上(这里采用printf,注意”#”与”%X”合用时自动为16 进制数增加”0X”前缀):
    for(int i = 32; i < 127; i++) {
    printf("[ %c ]: %3d 0x%#04X/n", i, i, i);
    }


    连接字符串
    sprintf 的格式控制串中既然可以插入各种东西,并最终把它们“连成一串”,自然也就能够连
    接字符串,从而在许多场合可以替代strcat,但sprintf 能够一次连接多个字符串(自然也可以同时
    在它们中间插入别的内容,总之非常灵活)。比如:
    char* who = "I";
    char* whom = "CSDN";
    sprintf(s, "%s love %s.", who, whom); //产生:"I love CSDN. "
    strcat 只能连接字符串(一段以’’结尾的字符数组或叫做字符缓冲,null-terminated-string),但有时我们有两段字符缓冲区,他们并不是以 ’’结尾。比如许多从第三方库函数中返回的字符数组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的’’来结尾。如果直接连接,不管是sprintf 还是strcat 肯定会导致非法内存操作,而strncat 也至少要求第一个参数是个null-terminated-string,那该怎么办呢?我们自然会想起前面介绍打印整数和浮点数时可以指定宽度,字符串也一样的。比如:
    char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
    char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
    如果:
    sprintf(s, "%s%s", a1, a2); //Don't do that!
    十有八九要出问题了。是否可以改成:
    sprintf(s, "%7s%7s", a1, a2);
    也没好到哪儿去,正确的应该是:
    sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN"
    这可以类比打印浮点数的”%m.nf”,在”%m.ns”中,m 表示占用宽度(字符串长度不足时补空格,超出了则按照实际宽度打印),n 才表示从相应的字符串中最多取用的字符数。通常在打印字符串时m 没什么大用,还是点号后面的n 用的多。自然,也可以前后都只取部分字符:
    sprintf(s, "%.6s%.5s", a1, a2);//产生:"ABCDEFHIJKL"
    在许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字符数组中的几个字符,这种动态的宽度/精度设置功能在sprintf 的实现中也被考虑到了,sprintf 采用”*”来占用一个本来需要一个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一样被提供出来,于是,上面的例子可以变成:
    sprintf(s, "%.*s%.*s", 7, a1, 7, a2);
    或者:
    sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2);
    实际上,前面介绍的打印字符、整数、浮点数等都可以动态指定那些常量值,比如:
    sprintf(s, "%-*d", 4, 'A'); //产生"65 "
    sprintf(s, "%#0*X", 8, 128); //产生"0X000080","#"产生0X
    sprintf(s, "%*.*f", 10, 2, 3.1415926); //产生" 3.14"


    打印地址信息
    有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的”%u”把他们打印出来:
    sprintf(s, "%u", &i);
    不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:
    sprintf(s, "%08X", &i);
    然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的”%p”:
    sprintf(s, "%p", &i);
    我觉得它实际上就相当于:
    sprintf(s, "%0*x", 2 * sizeof(void *), &i);
    利用sprintf 的返回值
    较少有人注意printf/sprintf 函数的返回值,但有时它却是有用的,spritnf 返回了本次函数调用
    最终打印到字符缓冲区中的字符数目。也就是说每当一次sprinf 调用结束以后,你无须再调用一次
    strlen 便已经知道了结果字符串的长度。如:
    int len = sprintf(s, "%d", i);
    对于正整数来说,len 便等于整数i 的10 进制位数。
    下面的是个完整的例子,产生10 个[0, 100)之间的随机数,并将他们打印到一个字符数组s 中,
    以逗号分隔开。
    #include
    #include
    #include
    int main() {
    srand(time(0));
    char s[64];
    int offset = 0;
    for(int i = 0; i < 10; i++) {
    offset += sprintf(s + offset, "%d,", rand() % 100);
    }
    s[offset - 1] = '/n';//将最后一个逗号换成换行符。
    printf(s);
    return 0;
    }
    设想当你从数据库中取出一条记录,然后希望把他们的各个字段按照某种规则连接成一个字
    符串时,就可以使用这种方法,从理论上讲,他应该比不断的strcat 效率高,因为strcat 每次调用
    都需要先找到最后的那个’’的位置,而在上面给出的例子中,我们每次都利用sprintf 返回值把这
    个位置直接记下来了。


    使用sprintf 的常见问题
    sprintf 是个变参函数,使用时经常出问题,而且只要出问题通常就是能导致程序崩溃的内存访
    问错误,但好在由sprintf 误用导致的问题虽然严重,却很容易找出,无非就是那么几种情况,通
    常用眼睛再把出错的代码多看几眼就看出来了。


    ?? 缓冲区溢出
    第一个参数的长度太短了,没的说,给个大点的地方吧。当然也可能是后面的参数的问
    题,建议变参对应一定要细心,而打印字符串时,尽量使用”%.ns”的形式指定最大字符数。


    ?? 忘记了第一个参数
    低级得不能再低级问题,用printf 用得太惯了。//偶就常犯。:。(


    ?? 变参对应出问题
    通常是忘记了提供对应某个格式符的变参,导致以后的参数统统错位,检查检查吧。尤
    其是对应”*”的那些参数,都提供了吗?不要把一个整数对应一个”%s”,编译器会觉得你
    欺她太甚了(编译器是obj 和exe 的妈妈,应该是个女的,:P)。

    strftime
    sprnitf 还有个不错的表妹:strftime,专门用于格式化时间字符串的,用法跟她表哥很像,也
    是一大堆格式控制符,只是毕竟小姑娘家心细,她还要调用者指定缓冲区的最大长度,可能是为
    了在出现问题时可以推卸责任吧。这里举个例子:
    time_t t = time(0);
    //产生"YYYY-MM-DD hh:mm:ss"格式的字符串。
    char s[32];
    strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));
    sprintf 在MFC 中也能找到他的知音:CString::Format,strftime 在MFC 中自然也有她的同道:
    CTime::Format,这一对由于从面向对象哪里得到了赞助,用以写出的代码更觉优雅。

    展开全文
  • 科技成果转化为生产力难在哪里?

    千次阅读 2016-03-26 19:20:39
    科技成果转化为生产力难在哪里? ——与吴祖垲院士对话 吴祖垲是中国工程院院士,著名真空器件工程专家。他先后参与创办南京华东电子管厂、成都红光电子管厂和咸阳彩虹显像管厂,我国日光灯管、黑白显像管和...

    科技成果转化为生产力难在哪里?

    ——与吴祖垲院士对话

    吴祖垲是中国工程院院士,著名真空器件工程专家。他先后参与创办南京华东电子管厂、成都红光电子管厂和咸阳彩虹显像管厂,为我国日光灯管、黑白显像管和彩色显像管等电真空器件的研制,开发,到大量生产做出了重大贡献。


    战略问题:理论和应用谁重要


    记者:多年来,科技成果如何转化为生产力一直是大家关心的问题。您在生产第一线从事科技工作60多年,并有在前苏联、美国、日本、法国和荷兰等国工作、学习和考察的经历,对这一问题的思考应该更深刻和实际。


    吴祖垲:近些年来,我一直在思考这一问题,这是一个关系我国工业能否持续健康发展的大问题。我认为,首先要明确科研的方向,到底是应该重“理论”还是重“应用”?这是一个国家的科技决策的战略问题。


    这方面,我自己有切身体会。早在1956年时,我参加了我国12年科学规划,那时科学院系统和电子工业部门对发光材料就有不同的看法。工业部门认为,对发光材料的研究应着重阴极射线发光及光致发光,主要是当时用这两大类材料的日光灯在美国已大量生产,彩色显像管已开始生产,这两种用途宽广的材料的质量改进、品种的发展,将对国民经济发展产生重大的影响。而当时科学院则认为这两大类材料早已成熟,没有研究的必要,而应该对作为新型材料的电致发光材料的发光机理进行深入研究。随着时间的推移,阴极射线及光致发光材料有了重大的突破和发展,尤其是在1963年美国Sylvania公司研制成功红色稀土发光材料(YVO4:Eu)用于彩色显像管,可使白场发光效率提高1-2倍;随着稀土发光材料不断发展,现在又用于紧凑型日光灯(亦称节能灯),提高了发光功率,改进了性能。如今彩色显像管及彩色显示管的全世界年产量已达2。5亿多只,产值接近250亿美金,另外,日光灯和节能灯全世界的年产量也已超过40亿只,产值大约接近100亿美金。相反,电致发光材料却发展不快,前些年其途局限于仪表显示和体育场馆的计分牌及少数军用产品而已,其产值仅数亿美金,时间过了近50年,最近OLED才有了新的进展。这个事例提醒我们,科研的方向应该着重于应用,而不是着重于以发表论文为目的的理论研究。


    关于这个问题,已故的两院外籍院士田长霖博士1983年在西北工业大学演讲时说过一段话,就很有说服力。他说:“英国获诺贝尔奖金的科学家人数较多,但是它在发达国家中,工业是最落后的,我们不要向它学;法国觉悟较早,转向重视应用研究,所以它的工业发展比英国快;美国有钱,舍得在科研上花钱,我们不能向它学;日本重应用,重视生产技术的研究,所以它的工业发展很快,日本的彩电、半导体工业、汽车工业已超过美国,电子计算机和航空工业亦将赶上美国,我们应该向它学。”


    核心问题:科研与生产“两张皮”



    记者:近20年来,我国非常重视科研工作,投入不断增加,成果成千上万,可是真正转化为生产力的比例却很低,您认为还有什么原因?


    吴祖垲:科研体制是科研成果不能及时转化为生产力的核心问题。近年来,我国一直致力于科研体制改革,但科研与生产互相脱节,“两张皮”问题仍然严重。我把这一现象概括成“一是头重脚轻根底浅,二是两断层”。所谓头重脚轻根底浅,就是说我国的科研上层非常庞大,有中国科学院、国防科委系统、工业部门的研究所,还有大专院校的研究所。然而在基层却很少或没有相互匹配的开发试验机构。所谓两断层,即科研部门和工业部门各不相关,没有正常的渠道相通,这是第一个断层;工业部门有不少的研究所,但是大中型企业却很少有开发试验部门与之相适应,这就是第二个断层。例如,原电子工业部上层有50多个研究所,但工厂有开发试验机构的不多,有的是名存实亡,呈倒金字塔形。这种“两张皮”现象导致科研单位游离于企业之外,企业创新能力较弱,在技术上不能持续进步,产品的性能和价格不能满足社会的需求。


    记者:发达国家存在“两张皮”问题吗?


    吴祖垲:发达国家也有,但很少。这主要是由于发达国家的科研系统呈金字塔形。它们也有国家的研究院所,但大量的科研实体却集中在大中型企业里,80%的科研工作在大企业中完成。从工业的基础研究、应用研究、开发试验、试生产到大量生产都在一个系统里完成的,企业的开发试验机构非常庞大和完备,所以科研成果就能很快地转化为商品生产。几年前我曾查阅了日立公司的组织机构,日立公司在全球50家大企业中名列前茅,其产品既有重型机械、原子能发电站、火力发电站,也有家用电器、计算机、IC及半导体等电子器件。由于产品种类多,所以日立公司有近10个研究所,如中央研究所、日立研究所、能源研究所、机械研究所、生产技术研究所、微电子设备研究所等等。在各事业部还有专门的开发中心,下属的大工厂里还有开发试验部。


    在发达国家,如果科研单位的项目有明确的产业化目标,那么项目开始时,生产单位的科技人员就会参与科研工作,到了一定阶段,科研部门的科技人员就到生产单位共同搞开发试验,直到试生产。


    现实问题:引进和创新不协调


    记者:全国科技经费投入统计公报表明,2003 年我国研发投入1539.6 亿元,其中各类企业投入 960.2 亿元,占62%。相对来说,企业的研发投入已经不低了,可为什么企业的研发能力仍然较弱?


    吴祖垲:企业的研发投入有不少水分。由于自身研发能力的局限,绝大多数企业走的是“引进型”的技术创新路子,大规模地引进国外先进技术,使我国工业和经济得到迅速发展,其成绩是有目共睹的。但是,在技术引进的过程中,多数企业的主要资金和精力用于硬件设备和生产线的进口,忽视技术专利和专有技术的引进,缺乏对引进技术的系统集成和综合创新。分析数据显示,我国大中型企业引进技术的费用往往比消化吸收费用高10多倍。


    只是借鉴,没有创新,没有掌握核心技术,这是我国目前工业发展中的一个软肋。如果一个企业只引进而不消化吸收和创新,势必陷入“引进――过时――再引进”的恶性循环,将长期依赖国外,非立国之本。我国是世界制造大国,但不是制造强国,作为“世界工厂”,没有多少值得骄傲的地方。我国彩色显像管工业之所以能有所发展,关键是咸阳彩虹彩色显像管总厂在建厂开工时就实现了零部件及其主要原材料国产化,使彩管成本大幅度下降,在世界市场上有了很大的竞争力,在引进消化或创新上迈出了一大步。但新品开发却在相当长的一段时间没有很大的进展,近年来才有所改变。


    记者:说到彩管工业,您是这方面的专家,我有一个问题想请教:中国和韩国的显像管产业都是从日本引进技术起步,为什么中国进步不大,而韩国在许多方面已超过日本?


    吴祖垲:我国生产黑白显像管早于韩国5—6年,彩管几乎与韩国同时从日本引进,如今韩国不仅在中国大陆建厂生产彩管,而且其等离子显示屏、液晶显示屏技术已接近或超过了日本和技术发源地美国。为什么中韩两国会有如此大的差距?这是因为韩国在引进技术时下了大本钱,聘请了许多日本专家协助,建立起了自己的研发体系,具备了自力更生开发新技术的能力。而我国企业却不停地引进先进技术,较少自主创新。一个日本专家在深圳说过一番让我刻骨铭心的话,他说:“你们中国人(大概指深圳的)现在都在享福,我们日本人象你们现在情况的时候,还在吃苦,美国人偷懒,今天的事拖明天,明天拖后天,我们日本人今日事今日毕,而韩国却说我们日本人偷懒。”可见韩国人比日本人还能吃苦。我们中国人真该警醒了。 


    基础问题:高技术不是空中楼阁



    记者:10多年来,我国一直致力于发展高技术,实现产业化。可是现在回头看看,我们会发现,我国高技术产业的发展似乎并不尽如人意。这是为什么?


    吴祖垲: 我们有不少人高呼高技术,殊不知高技术仍是靠坚强和完整的基础工业来支持的,如果高技术产品的核心零部件和元器件要依靠进口,那是来料加工,是虚的高技术,是空中楼阁。


    基础工业指的是化学工业、冶金工业、机械工业及某些轻工业,现在连建筑在这些基础工业之上的电子工业亦成为了基础工业。美国的高技术为什么容易转化为生产力?那就是因为美国有强大基础工业。第二次世界大战时,美国实施制造原子弹的曼哈顿计划时,炼铀的技术就是采用的美国西屋公司的现成技术,大大加速了原子弹的试验成功并投入生产。40年代初,西屋公司为提高钨丝白炽灯的发光效率,设法以铀丝来替代钨丝。铀虽然提炼出来了,但它的熔点却比钨丝低。这种设想虽然失败了,但西屋公司却掌握了炼铀技术,为原子弹的研制打下了工业基础。这样的例子很多,如:美国RCA公司试制成功彩色显像管,大量投产时,要用一种有机膜材料改进产品质量,它就采用了另一家公司现成的聚丙烯酸树脂的共聚物,使得彩色显像管很快就投入了生产。而我们在上世纪70年代试制彩色显像管时,一切都需要从头做起,其难度可想而知。


    记者:从您举的两个例子可以看出,基础工业也有高技术。


    吴祖垲:是这样的。基础工业还有精益求精和专业化生产的问题。1937年我大学毕业就到湖南一个电子管工厂工作,当时用到了美国Acheson公司的石墨乳,过了51年后我在咸阳彩色显像管厂又发现用于彩管屏幕涂黑底的石墨乳,亦是从美国Acheson公司进口的,但是质量提高了,它的石墨乳制造实际上已经采用了纳米技术。这家公司成立于1907年,迄今近100年了,它之所以能存在,就是依靠技术不断进步,精益求精。


    同样,爱迪生发明白炽灯迄今己100多年,美国GE公司和荷兰飞利浦公司都以白炽灯起家,它们精益求精,坚持电光源不放,不断提高发光效率,延长使用寿命,不断发展新产品,从炭丝灯改为钨丝灯,从真空到充氮,从充氮到充氩气,而到充氪气,还有卤素灯。气体放电灯从低汽压放电的荧光灯发展到超高压UHP的水银灯和高强度汽体放电HID灯。某些特殊的荧光灯如CCFL正是用在TFT-LCD为背景光源,UHP及HID用于高端背投电视,LCOS及DMD,而且UHP及HID两种光源的寿命严格的讲仅4000小时,每只的零售价为350-400美金,以上这些特殊光源都是高端显示器的重要元器件。你能说这些基础工业没有高技术吗?


    在我国,工厂为了提升级别,灯泡厂改为电子管厂,将灯泡逐步由国营厂转交给地方国营厂,又转移到乡镇企业,产品质量不断下降。最近我在深圳买到了一只白炽灯,才用了不到40分钟就寿终正寝了。依照这样的思路,我国的基础工业很难强大起来。因此,我们在发展高技术的同时,对基础工业还得有的放矢,进行补课。


    根本问题:决策者的决心



    记者:请您谈谈人在科技成果转化为生产力的过程中的作用?


    吴祖垲:一个科技成果要转化为生产力,与决策者有没有决心以及决心的大小,有着很大的关系。我国能在极其困难的条件下研制成功“二弹一星”,是与我国的最高领导的决心分不开的。美国原子弹的研制也一样。当时专家们提出了5种方案分离U235,为了争取时间,5种方案同时进行。其中的一个方案是采用强电磁场分离的方法,强的电磁场要用到大电流的线圈,那就需要良好导电率的导线。那时还没有超导材料,只有用银为导体。美国政府就把国库中的所有银锭拨给有关部门,制成银质线来产生强大的电磁场,最终制成了原子弹。


       现在大家都强调科学技术是第一生产力,但真正落到实处时,有的领导宁愿把钱花在搞形象工程上,也不愿意投资见效慢的科技开发。这个问题,应引起各级领导的高度重视。



    展开全文
  • 递归转化成迭代的通用技术

    万次阅读 2011-05-14 14:36:00
    理论上讲,只要允许使用栈,所有的递归程序都可以转化成迭代。但是并非所有递归都必须用栈,不用堆栈也可以转化成迭代的,大致有两类尾递归:可以通过简单的变换,让递归作为最后一条语句,并且仅此一个递归调用。...

    从理论上讲,只要允许使用栈,所有的递归程序都可以转化成迭代。

    但是并非所有递归都必须用栈,不用堆栈也可以转化成迭代的,大致有两类

    1. 尾递归:可以通过简单的变换,让递归作为最后一条语句,并且仅此一个递归调用。

     

    1. 自顶向下->自底向上:对程序的结构有深刻理解后,自底向上计算,比如 fibnacci 数列的递归->迭代转化。

     

     

    对于非尾递归,就必须使用堆栈。可以简单生硬地使用堆栈进行转化:把函数调用和返回的地方翻译成汇编代码,然后把对硬件 stack 的  push, pop 操作转化成对私有 stack 的 push, pop ,这其中需要特别注意的是对返回地址的 push/pop,对应的硬件指令一般是 call/ret。使用私有 stack 有两个好处:

    1. 可以省去公用局部变量,也就是在任何一次递归调用中都完全相同的函数参数,再加上从这些参数计算出来的局部变量。
    2. 如果需要得到当前的递归深度,可以从私有 stack 直接拿到,而用递归一般需要一个单独的 depth 变量,然后每次递归调用加 1。

    我们把私有 stack 元素称为 Frame,那么 Frame 中必须包含以下信息:

    1. 返回地址(对应于每个递归调用的下一条语句的地址)
    2. 对每次递归调用都不同的参数

    通过实际操作,我发现,有一类递归的 Frame 可以省去返回地址!所以,这里又分为两种情况:

    • Frame 中可以省去返回地址的递归:仅有两个递归调用,并且其中有一个是尾递归。

       

      • Frame 中必须包含返回地址的递归,这个比较复杂,所以我写了个完整的示例:
        • 以MergeSort为例,因为 MergeSort 是个后序过程,两个递归调用中没有任何一个是尾递归
        • MergeSort3 使用了 GCC 的 Label As Value 特性,只能在 GCC 兼容的编译器中使用
        • 单纯对于这个实例来说,返回地址其实只有两种,返回地址为 0 的情况可以通过判断私有栈(varname=stk)是否为空,stk为空时等效于 retaddr == 0。如果要精益求精,一般情况下指针的最低位总是0,可以把这个标志保存在指针的最低位,当然,如此的话就无法对 sizeof(T)==1 的对象如 char 进行排序了。
        •  
      展开全文
    1. CentOS7使用virt-p2vRHEL6.7的物理机转化为kvm虚拟机 准备环境: 待转的物理机P:RHEL6.7 安装有virt-v2v工具的conversion server:CentOS7.2+virt-v2v-1.28.1-1.55.el7.centos.x86_64 下载/制作p2v iso U盘启动:...
    2. 都知道旋转矩阵表达的是刚体(坐标系{B})相对参考坐标系{A}的姿态信息,那如何利用已知的旋转矩阵,{A}旋转一定角度变成与{B}一样的姿态呢?有几种方法:固定角旋转、欧拉角旋转、angle-axis表达法、Quaternion...
    3. NFA转化DFA

      千次阅读 2012-09-06 22:51:17
      NFA转化DFA ...但是,NFA到DFA的转化就不是那么简单了,实际上,在计算理论中,它属于ExpSpace问题,是一类比NP问题更难的问题。 往简单了说,因为NFA的转移函数的返回值是个state集合,如果NFA的stat
    4. 什么是转化医学(转化研究)?

      千次阅读 2019-09-24 12:10:36
      转化医学(Translational Medicine),也称转化研究(Translational Research, TR)是二者连接起来的一种新的理念。目的是基础研究与解决患者实际问题结合起来,其基本特征是多学科交叉合作,针对临床提出...
    5. lab2主要讲虚拟内存->物理内存的变换,通过一定的函数来实现...首先,明确一点,在程序里面的所有地址,都是虚拟地址,程序里面是不会出现物理地址的,就算是物理地址,CPU也会把它当做虚拟地址,通过MMU转化为物理地
    6. 空间RSSR机构可以转化为轴线相交一点的球面4R机构,然后推导出空间RSSR机构主动曲柄件时,空间RSSR机构转化为4R机构的各个设计参数应满足的条件,为实际工程应用提供理论依据。根据空间RSSR机构转化为球面4R机构的...
    7. 针对实际工作环境中数据文件格式繁多,结构与标准不统一,与既定数据库之间互转化难的问题,提出了一种通用的、新型的结构化数据与关系数据库互转化的思路,并从理论和结构上对该思路进行了构思与设计,形成了一套新...
    8. 耗散理论

      千次阅读 2018-07-29 16:05:17
      摘要:耗散结构理论是研究开放系统在远离平衡状态的非线性区从混沌而有序转化系统引向自我完善的机理和规律的理论。对我们在经营管理实践中,深入、透彻地认识和分析企业,掌握其内在发展规律具有现实的指导意义...
    9. 这样g(x)就可以转化为f(y)=,y>,你可以把y和a分别回带一下,看看等不等于原来的g(x)。用内积的形式写你可能看不太清楚,实际上f(y)的形式就是: g(x)=f(y)=ay 在任意维度的空间中,这种形式的函数都是一个...
    10. 应用委托代理理论,建立了基于企业实力和风险分析的高校科技成果转化的数学模型;通过对模型的分析,揭示了企业实力、投资风险和道德风险是高校科技成果转化低效的3个制约因素,并进一步对其成因进行了分析;最后...
    11. 计划行为理论(TPB,Theory of Planned Behavior)

      万次阅读 多人点赞 2014-04-01 14:39:28
      计划行为理论(TPB,Theory of Planned Behavior)由Ajzen(1985)所提出,并由Fishbein & Ajzen于1975年所提出的理性行为理论(TRA,Theory of Reasoned Action)演变而来的,理性行为理论主要用来预测和了解人类的...
    12. 说起来这门技术大多是秀的成分高于实际,但是呢,其也可以作为图像增强的工具,看到一些比赛拿他作训练集扩充,还是一个比较好的思路。如何在caffe上面实现简单的风格转化呢?好像网上的博文都没有说清楚,而且笔者也...
    13. 今天又重新复习了一下进程...这些创建子进程的函数本质上都完成了相同的功能——调用进程复制一份,得到子进程。(可以通过选项参数来决定各种资源是共享、还是私有。)那么既然调用进程处于TASK_RUNNING状态(否则
    14. 常见的各种人提出的理论

      千次阅读 2012-11-19 09:38:19
      1、威廉·大内的Z理论(1981)   Z理论( Theory Z)是由美国日裔学者威廉·大内(一译乌契,William Ouchi)在1981年出版的《Z理论》一书中提出来的,其研究的内容为人与企业、人与工作的关系。  威廉·...
    15. 数仓理论

      千次阅读 2019-02-28 19:45:23
      ...其实数据仓库本身并不“生产”任何数据,同时自身也不需要“消费”任何的数据,数据来源于外部,并且开放给外部应用,这也是什么叫“仓库”,而不叫“工厂”的原因。因此数据仓库的基本架...
    16. 派生类与基类间的转化

      千次阅读 2012-07-10 18:31:38
      派生类对象传递给希望接受基类引用的函数,此时并不发生派生类到基类的类型转化。因为引用直接绑定到派生类上,对象并没有复制,只是派生类的基类部分的地址传递给基类型的引用。 派生类对象传递给接受基类...
    17. 第五章 关系数据理论  一、选择题  1. 为了设计出性能较优的关系模式,必须进行规范化,规范化主要的理论依据是(A) 。 A. 关系规范化理论 B. 关系代数理论 C.数理逻辑 D. 关系运算理论  2. 规范...
    18. 软件测试的理论基础

      千次阅读 2018-06-30 20:20:38
      软件(系统软件、应用软件)2:计算机网络——OSI七层模型:应用层:所有应用程序的网络在此展开表示层:表示数据形式,完成对传输数据的转化(数据的加密及解密)会话层:负责建立、维护、拆除会话(session缓存)...
    19. 专家系统/模糊理论/神经网络/遗传算法相关基础知识
    20. TCI 靶控输注理论

      千次阅读 2016-10-26 09:14:21
      TCI 靶控输注理论 临床意义
    21. 【1017】需求分析的“Y理论

      千次阅读 2011-06-07 17:52:00
      “需求分析”的过程到底是什么?“用户需求”、“产品需求”...这个过程可以形象化为“Y”,“需求分析”的过程就是经历图中的“1 –> 2 — >3”,把“用户需求”转化为“产品功能”。 需求分析的Y对图做几点解释:
    22. 数据是存放在物理内存中的,而程序中使用的是虚拟内存并通过虚拟内存地址来访问数据和代码的,那么操作系统是如何 虚拟内存地址映射成为实际的物理内存的呢?这是我们这篇文章要详细介绍的问题。以X86的32位系统...
    23. 用户行为理论

      千次阅读 2019-08-06 12:25:17
      比如 IP、PV、页面停留时间、跳出率、回访者、新访问者、回访次数、回访相隔天数、流失率、关键字搜索、转化率、登录率,等等。遇到这么多指标,所有的指标都要采用吗?什么指标该采用?什么指标又不该采用,各指标...
    24. 计算复杂性理论

      千次阅读 2019-06-09 00:24:03
      查看原文,点我 计算复杂性理论 在计算机算法中,计算复杂性是一个很重要的研究...计算复杂性理论通过引入数学计算模型来研究这些问题以及定量计算解决问题所需的资源(时间和空间),从而资源的确定方法正式化...
    25. 虽然说,这里提供了很多的直接产生array的方式,但是大部分情况我们都是会从list进行转换,因为在实际的处理中,我们需要从txt加载文件,那样直接读入的数据显示存放到list中,需要处理的时候我们转换到array,因为...

    空空如也

    空空如也

    1 2 3 4 5 ... 20
    收藏数 94,860
    精华内容 37,944
    关键字:

    如何将理论转化为实际