首页 > 编程语言 >【 Pro*C/C++ 】 Pro*C/C++ 编程

【 Pro*C/C++ 】 Pro*C/C++ 编程

时间:2024-07-24 23:53:55浏览次数:14  
标签:EXEC Pro 编程 C++ 编译 myfirst SQL Oracle

ProC/C++ 编程 1
一、Pro
C/C++ 简介 1
1.1、ProC/C++ 是什么 1
1.2、Pro
C/C++ 处理流程 2
二、ProC/C++ GCC 环境配置 3
2.1、Pro
C/C++ 预编译环境 3
2.2、GCC 编译器 5
三、开始编写第一个ProC++代码 5
3.1、第一个Pro
C++代码 5
3.2、ProC++代码预编译 6
3.3、GCC 编译 7
3.4、最后测试 8
四、复杂一些的Pro
C/C++代码 8
4.1、代码部分 8
4.2、代码编译 12
4.3、代码测试 14

一、ProC/C++ 简介
1.1、Pro
C/C++ 是什么
为了用户开发Oracle应用程序, Oracle提供了一套Oracle调用规范, 即Oracle Call Interface (OCI),但是比较难以掌握使用, 对于熟悉 C/C++ 的用户要编写Oracle应用程序, 还需要花很多时间去研究 OCI, 因此 Oracle 推出了一个在 C/C++ 代码中直接嵌入 SQL 的方法, 然后通过 Oracle 提供的预编译程序, 编译成SQLLIB的调用, 这就是 Pro*C/C++。
注意, SQLLIB 与 OCI 是不同的, SQLLIB 主要是保含一系列函数的Oracle 应用程序运行库,用于应用程序执行或预编译时调用,其本身并不是Oracle 标准接口API,随着Oracle 版本的变化SQLLIB 的函数调用格式、用法、参数等也有可能变化。如果一个项目中需要一个比较通用的、平台一致性好的、不随数据库版本变化而变化的一系列封装函数,最好的建议是使用Oracle Call Interface (OCI) 进行标准C 语言的编程处理。

1.2、ProC/C++ 处理流程
C/C++ 源代码 =⇒ 源代码中嵌入SQL =⇒ 通过 Pro
C 预编译命令产生新的源代码
=⇒ 通过正常的C/C++编译器编译连接应用程序 =⇒ 运行应用程序

二、ProC/C++ GCC 环境配置
2.1、Pro
C/C++ 预编译环境
当您安装 Oracle 数据库产品的时候,ProC/C++的预编译环境缺省就为我们安装好了,我们这里以安装 Oracle 10G 版本为例. 在 Oracle_Home的 Bin 目录下, 您可以找到预编译程序 proc.exe, 这个就是用来预编译您有在C/C++代码中嵌入SQL的文件的. 该编译程序用到了 Oracle_Home下的precomp\public 目录中的 .h 头文件, 在正真编译生成可执行文件时又会用到 precomp\lib 的一个 .lib 库文件.
我们进入 command 窗口,看看 proc 编译命名的参数:
Pro
C/C++编译命令参数(10G)
C:\oracle\product\10.2.0\db_2\BIN>proc

Pro*C/C++: Release 10.2.0.1.0 - Production on Mon Feb 23 16:22:29 2009

Copyright © 1982, 2005, Oracle. All rights reserved.

System default option values taken from: C:\oracle\product\10.2.0\db_2\precomp\admin\pcscfg.cfg

Option Name Current Value Description

auto_connect no Allow automatic connection to ops$ account
char_map charz Mapping of character arrays and strings
close_on_commit no Close all cursors on COMMIT
cmax 100 CMAX Value for connection pool
cmin 2 CMIN Value for connection pool
cincr 1 CINCR Value for connection pool
ctimeout 0 CTIMEOUT Value for connection pool
cnowait 0 CNOWAIT Value for connection pool
code cpp The type of code to be generated
comp_charset multi_byte The character set type the C compiler supports
config default Override system configuration file with another
cpool no Support connection pooling
cpp_suffix cc Override the default C++ filename suffix
dbms native v6/v7/v8 compatibility mode
def_sqlcode no Generate ‘#define SQLCODE sqlca.sqlcode’ macro
define none Define a preprocessor symbol
duration transaction Set pin duration for objects in the cache
dynamic oracle Specify Oracle or ANSI Dynamic SQL Semantics
errors yes Whether error messages are sent to the terminal
errtype none Name of the list file for intype file errors
events no Support publish-subscribe event notifications
fips none FIPS flagging of ANSI noncompliant usage
header none Specify file extension for Precompiled Headers
hold_cursor no Control holding of cursors in the cursor cache
iname none The name of the input file
include none Directory paths for included files
intype none The name of the input file for type information
lines no Add #line directives to the generated code
lname none Override default list file name
ltype short The amount of data generated in the list file
maxliteral 1024 Maximum length of a generated string literal
maxopencursors 10 Maximum number of cached open cursors
mode oracle Code conformance to Oracle or ANSI rules
native_types no Support for native float/double
nls_char none Specify National Language character variables
nls_local no Control how NLS character semantics are done
objects yes Support object types
oname none The name of the output file
oraca no Control the use of the ORACA
pagelen 80 The page length of the list file
parse none Control which non-SQL code is parsed
prefetch 1 Number of rows pre-fetched at cursor OPEN time
release_cursor no Control release of cursors from cursor cache
select_error yes Control flagging of select errors
sqlcheck SEMANTICS Amount of compile-time SQL checking
sys_include none Directory where system header files are found
threads no Indicates a multi-threaded application
type_code oracle Use Oracle or ANSI type codes for Dynamic SQL
unsafe_null no Allow a NULL fetch without indicator variable
userid none A username/password [@dbname] connect string
utf16_charset nchar_charset The character set form used by UTF16 variables
varchar no Allow the use of implicit varchar structures
version recent Which version of an object is to be returned
win32_threads no Support windows default local threading
PCC-F-02135, CMD-LINE: User asked for help

这些命令参数选项,除了直接在命令行参数中指定外,您也可以通过 precomp\admin\psccfg.cfg 文件中进行指定, 下面是一个样例:
ltype=short
code=cpp
cpp_suffix=cc
parse=none
SQLCHECK=SEMANTICS
这里我们介绍其中的三个参数:
• code=cpp 这个参数表明我们通过 proc 预编译命令产生的代码文件是符合 C++ 规范的,如果您是在标准C环境中使用, 那么您可以指定 code=ansi_c
• cpp_suffix=cc 这个参数让 proc 命令产生的文件以 .cc 作为文件扩展名
• SQLCHECK=SEMANTICS 这个参数用于指示在预编译的时候是否要检查嵌入的SQL的语法,您可以设置 NONE 表示不检查(10G中中已经不再支持这个值了,至少设置为 SYNTAX), SEMANTICS 表示检查语义(也就是检查数据库表名,列名是否存在等)
2.2、GCC 编译器
在 Windows 环境中, 您可以选择使用微软的 VC 编译器, 或者 Bland公司的 BC 编译器. 我们这里使用 GCC 1) 编译器, GCC 编译器的安装可以直接从 http://gcc.gnu.org 这里下载, 最新提供一个在Windows下快速安装的工具程序.这里我们采用了 Dev-CPP 的开发环境, 这个开发环境中包含了 GCC, 下载地址见 http://www.bloodshed.net/dev/devcpp.html
三、开始编写第一个ProC++代码
3.1、第一个Pro
C++代码
本文中涉及到的 C++ 知识不做过多介绍,已经超出了本文范围.
编写一个 Oracle 登陆程序(我们这里使用 C++ 代码, 当然您也可以使用 标准C 代码):
1: using namespace std;
2: #include <iostream.h>
3: #include “sqlca.h” // SQL Comunication Area
4:
5: EXEC SQL BEGIN DECLARE SECTION;
6: char uid = “scott/tiger@orcl10g”;
7: EXEC SQL END DECLARE SECTION;
8:
9: int main()
10: {
11: EXEC SQL CONNECT :uid;
12: if (sqlca.sqlcode != 0)
13: cout<<sqlca.sqlerrm.sqlerrmc<<endl;
14: else
15: cout<<“Success.”<<endl;
16: EXEC SQL COMMIT WORK RELEASE;
17: }
第5,7行代码表示要定义SQL宿主变量, 这里边的变量的定义方式依照 C++ 中的方式定义.这些变量除了能够在正常的 C++ 代码中使用外, 也能使用在嵌入的SQL语句中, 因此被成为宿主变量
第 6 行就申明了一个 SQL 宿主变量
第11行为连接数据库的指令.
第12行判断SQL通讯区变量 sqlca 中的信息, 以检查sql语句执行是否成功, 这里检查是否连接成功, 成功执行 sqlca.sqlcode 值为 0, 当有错误发生时, sqlca.sqlerrm 这个子结构保存了相应的错误讯息.
第16行为提交工作并释放资源(也即断开连接).
我们把这个文件保存在 C:\proc 目录下, 命名为 myfirst.pc (通常我们编写的Pro
C 程序以 .pc 结尾)
3.2、Pro*C++代码预编译
首先设置预编译命令的路径,然后再行编译
C:>set ORACLE_HOME=C:\oracle\product\10.2.0\db_2

C:>set path=%ORACLE_HOME%\bin

C:>cd proc

C:\proc>dir /b
myfirst.pc

C:\proc>proc myfirst.pc

Pro*C/C++: Release 10.2.0.1.0 - Production on Wed Feb 25 13:58:52 2009

Copyright © 1982, 2005, Oracle. All rights reserved.

System default option values taken from: C:\oracle\product\10.2.0\db_2\precomp\admin\pcscfg.cfg

C:\proc>dir /b
myfirst.cc
myfirst.lis
myfirst.pc

C:\proc>

以上已经与编译成功,我们可以看到新产生了 myfirst.cc 文件, 这个文件就是将嵌入的SQL指令预编译成为标准的ORACLE库函数调用后的文件.您可以查看该文件内容.
3.3、GCC 编译
在进行预编译产生正常的C++代码文件后, 接下来, 我们只需要用 C++ 编译器编译这个 .cc 文件即可得到我们的可执行文件. 我们首先需要设置一下 Path, 以便找到我们的编译器, 我的 gcc 编译器在 c:\Dev-Cpp\bin 目录下, 由于这里使用的是 C++ 的编程, 所以我使用 g++ 编译命令
C:\proc>set path=C:\Dev-Cpp\bin;%path%

C:\proc>g++ myfirst.cc
myfirst.cc:145:19: sqlca.h: No such file or directory
myfirst.cc: In function int main()': myfirst.cc:167: error: sqlca’ undeclared (first use this function)
myfirst.cc:167: error: (Each undeclared identifier is reported only once for each function it appears in.)

这里出错了,因为 sqlca 这个结构变量没有找到, 实际上是没有找到 sqlca.h 这个头文件, 这个头文件在 %ORACLE_HOME%\precomp\public 目录下, 因此我们通过命令行指定这个位置:
C:\proc>g++ myfirst.cc -I %ORACLE_HOME%\precomp\public
C:\DOCUME1\nyfor\LOCALS1\Temp/ccgLbaaa.o(.text+0x2b9):myfirst.cc: undefined reference to `sqlcxt’
collect2: ld returned 1 exit status
C:\proc>

依然有错误,提示找不到 sqlcxt 的引用, 这个是在链接的时候发生的错误, 链接时需要一个Oracle库文件, 这个库文件位置在 %ORACLE_HOME%\precomp\lib目录中,文件名为: orasql10.lib, Oracle 9i 的文件名为 orasql9.lib
我们指定库文件路径及库文件后重新编译:
C:\proc>g++ myfirst.cc -I %ORACLE_HOME%\precomp\public -L %ORACLE_HOME%\precomp\LIB -l orasql10

C:\proc>dir /b
a.exe
myfirst.cc
myfirst.lis
myfirst.pc

C:\proc>

至此, 我们成功生成了一个可执行文件 a.exe , 这个文件可以用来测试登陆.
3.4、最后测试
当我们生成好了可执行文件后, 我们开始测试,
C:\proc>a
Success.
当我们把 Oracle Listener 停掉后再行测试
C:\proc>a
ORA-12170: TNS:Connect timeout occurred

四、复杂一些的ProC/C++代码
4.1、代码部分
这里我们直接在代码中编写注释, 以阐释Pro
C/C++中的一些基本指令的用法
using namespace std;
#include
#include “sqlca.h” //引入 SQL 通讯区

//以下申明一个宿主变量,这是一个全局的变量,这个变量在C代码中和正常的变量一样使用,
//在嵌入SQL语句中,在变量名前追加冒号:来引用该变量.
EXEC SQL BEGIN DECLARE SECTION;
//只有包含在这之间申明的变量才能用于嵌入SQL代码中
char *uid = “scott/tiger@//192.168.8.35:1522/orcl10”;
EXEC SQL END DECLARE SECTION;

//这里申明了一个函数,后面会做说明,代码实现在最后
void sql_error();
int main()
{
/*
这条指令指示嵌入SQL执行发生错误的时候(不包含NO_DATA_FOUND例外)转向执行的C函数
这个指令还有其它一些语法:
EXEC SQL WHENEVER SQLERROR CONTINUE; 继续执行下一条语句
EXEC SQL WHENEVER SQLERROR STOP; 停止应用程序的执行
EXEC SQL WHENEVER SQLERROR GOTO label; 跳转到指定的标号处运行
初始状态为 CONTINUE
*/
EXEC SQL WHENEVER SQLERROR DO sql_error();

/*
这条指令连接数据库, 常用的连接方法有两种:
一是将用户名和密码存放在两个宿主变量中, 采用 IDENTIFIED BY 子句:
EXEC SQL CONNECT :username IDENTIFIED BY :password ;
一是将用户名和密码按照“username/password”方式(在用户名和密码中用反斜线做分隔的字符串)存放在一个宿主变量中:
EXEC SQL CONNECT :usernameandpwd;
*/
EXEC SQL CONNECT :uid;
cout<<“Database Connected…”<<endl;
EXEC SQL WHENEVER SQLERROR CONTINUE;

//下面这条指令是执行一条本机动态SQL语句,语法和PL/SQL中类似
EXEC SQL EXECUTE IMMEDIATE 'drop table t_emp';

//前面代码当SQL执行发生错误时设置的CONTINUE,我们在下一条语句检查执行结果
if (sqlca.sqlcode == 0)    // sqlcode 为 0 表示执行成功.
{
    cout<<"Table T_EMP droped."<<endl;
}
EXEC SQL WHENEVER SQLERROR DO sql_error();

//以下是嵌入的普通的DDL语句,执行完后我们没有检测 sqlca.sqlcode ,
//是因为前面我们设置了出错时进行捕获并执行 sql_error() 函数
//我们在 sql_error 函数中进行错误处理.
EXEC SQL create table t_emp as select empno,ename,sal from emp where 1 = 0;
cout<<"Table T_EMP created."<<endl;

/*
下面在 main 函数内申明SQL宿主变量,这里的就是局部变量了,只能用在函数 main 内部以下申明了一些数组变量,供我们用来存储查询语句返回的多行数据,在 PL/SQL 中我们也曾使用bulk collect into 子句来批量 fetch 数据;当然我们也可以不定义数组,而定义单个变量,这样每次就只能获取一条数据.
*/
EXEC SQL BEGIN DECLARE SECTION;
int empno[5]; //存放 EMPNO 字段
char ename[5][11];
/*存放 ENAME 字段,因为在 C 中字符串是要以 ‘\0’ 结尾的,所以比我们在DB中定义的10个字节的长度要多定义一个字节, 这点要记住了. */
float sal[5]; //存放 SAL 字段

/下面这个数组定义的用途做个描述:
在 Oracle 的数据值中, 有 NULL 这样一种特殊的值, 而在 C 中并没有这种值, 为了表明从Oracle中获取的值是否为 NULL, 特别定义了一个指示变量(Indicator),在数据返回过程中, 通过设置这个指示器变量,以让应用程序知道这个值是否为 NULL 值,具体用法是将这个指示器变量直接跟在变量后面,数据返回后检查指示器,如果为 -1 表示值为 NULL; 为 0 表示值为非 NULL,这时对应的变量值就是有效的;值大于 0 则表示返回值有被截断.
/
short sal_ind[5];

    int last_cnt;
    int fetch_cnt;

EXEC SQL END DECLARE SECTION;

//以下两句简单测试了一下 NO_DATA_FOUND 这个例外的处理
EXEC SQL WHENEVER NOT FOUND DO puts("Hi, Here is 'NO_DATA_FOUND' exception.");
EXEC SQL select empno,ename,sal into :empno,:ename,:sal :sal_ind from t_emp;
EXEC SQL WHENEVER NOT FOUND continue;

//下面语句我们从表中获取4条数据
EXEC SQL select empno,ename,sal+comm
           into :empno,:ename,:sal :sal_ind
           from emp where rownum <= 4;

/*
这里我们可以检查 sqlca.sqlcode 的值, 我们会发现其值为 1403,
检查 sqlca.sqlerrd[2] 值为 4, 表示查询获取到了 4 条记录.
注意!!! 为何这里sqlcod值为1403 ? 那是因为我们定义的数组容量为5,那么程序就会
帮助我们一次性要获取到5条记录, 而在获取第 5 条记录时,已经找不到数据,
因此就会出现 NO_DATA_FOUND, 而如果你这里修改 rownum <= 4 为 rownum <= 5
那么你会发现 sqlcode 不再是 1403, 而是 0, 再进一步, 如果你修改成 rownum <= 6
那么这里将会发生 TOO_MANY_ROWS 例外,这个例外会被 WHENEVER SQLERROR 捕获到,
因此这里就会转去执行 sql_error() 函数.
*/

cout<<"Empno\tEname\tSal\tIndicator?"<<endl;
for(int i=0; i < sqlca.sqlerrd[2]; i++)
{
    cout<<empno[i]<<'\t'<<ename[i]<<'\t'<<sal[i]<<'\t'<<sal_ind[i]<<endl;
}
/* 上面的数组数据中你会发现指示器有的为 -1 表明对应的 Sal 栏位值为 NULL,
   因为有些 comm 值为 null, 将 sal 直接加上 comm 后,则结果会出现 NULL 值
   对于 NULL 值的资料栏位, 我们会发现对应栏位的值是乱七八糟的, 实际上当数据库资料
   为NULL 值时, 程式根本不会去设置相应变量的值, 而只是设置指示器变量的值. 栏位变量的值
   仍然保留SQL执行之前的值. */

/*下面申明一个静态游标(Cursor), 显式游标的使用依然遵循定义,打开,资料获取,关闭四个动作 */
EXEC SQL DECLARE cur_emp CURSOR FOR
    select empno,ename,rownum * 100+comm from emp where rownum <= 8;

EXEC SQL OPEN cur_emp;
last_cnt = 0;  // last_cnt 用来保存上一次Fetch数据之后总共Fetch出的数据行数
do
{
    //以下语句只针对 sal 字段进行了 NULL 值的判断处理.
    EXEC SQL FETCH cur_emp into :empno,:ename,:sal :sal_ind;

    /*sqlca.sqlerrd[2] 对于 insert,update,delete 表示影响到的行数,
      对于 select 则表示Fetch到的数据的总行数, 尚未 Fetch 的数据不计入 */
    fetch_cnt = sqlca.sqlerrd[2] - last_cnt; // 得到本次 Fetch 的行数
    if (fetch_cnt == 0)

break; //本次未获取到数据则跳出循环

/* 注意上面不能判断 sqlca.sqlcode == 1403 成立就退出, 因为数组可以容纳 5个元素, 而实际上可能获取到 3 个元素, 那么这时sqlca.sqlcode是等于1403的. */

    last_cnt = sqlca.sqlerrd[2];
    cout<<"Data fetched "<<fetch_cnt<<" rows from EMP."<<endl;
    if (sqlca.sqlcode == 1403) last_cnt = 0;

    /*批量插入数据行,注意批量插入时必须指定要插入的行数,用 for 表明.
      假定这里我们去掉 for :fetch_cnt, 那么我们的Pro*C 预编译程序会根据
      插入值变量中的数组元素个数作为批量插入的行数,也即会插入数组中全部的元素
      除非你确定数组中全部的元素都要插入, 请务必指定要插入的行数.
      因为我们这里演示的是获取一批数据插入一批数据,在最后一批时可能只有少量几笔,
      所以这里我们对插入的行数进行了指定*/
    EXEC SQL for :fetch_cnt insert into t_emp values(:empno,:ename,:sal :sal_ind);
    cout<<"Data insert "<<fetch_cnt<<" rows into T_EMP."<<endl;

} while (last_cnt != 0);

/*注意上面循环末尾不能用 while (sqlca.sqlcode != 1403) 因为到达循环末尾时
  sqlca 的内容已经不再表示前面 fetch 的结果了,而是最后的那个 insert 语句的结果,
  我们在代码中做一个记录, 在Fetch出现1403时,将 last_cnt 置为 0, 用于最后退出循环的判断 */
EXEC SQL CLOSE cur_emp;

EXEC SQL COMMIT WORK RELEASE;
cout<<"Database Disconnected....."<<endl;

}
/*这个是错误处理函数的实现部分,在用指令:
EXEC SQL WHENEVER SQLERROR DO sql_error();
后即会在SQL执行出错时转向这个函数(NO_DATA_FOUND除外) */
void sql_error()
{
/*这里必须重置一下WHENEVER SQLERROR的处理方式,否则当错误处理代码中再次
出现SQL错误时将会陷入死循环, 当然如果这个错误处理函数中没有进行任何的SQL
操作, 那么不重置这个也没太大关系

标签:EXEC,Pro,编程,C++,编译,myfirst,SQL,Oracle
From: https://blog.csdn.net/yuzhangfeng/article/details/140676113

相关文章

  • C++语法10:C++实现0-1背包问题的动态规划解法
    动态规划(DynamicProgramming):解锁复杂问题的钥匙在算法设计与分析的广阔领域中,动态规划(DynamicProgramming,DP)无疑是一把锋利的剑,用于斩断复杂问题中缠绕的荆棘。它通过将大问题分解为小问题,并存储子问题的解来避免重复计算,从而高效地解决了一系列看似无解的难题。本文将从......
  • Java中的WebSocket编程:实时通信实现
    Java中的WebSocket编程:实时通信实现大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!实时通信在现代应用中变得越来越重要,从即时聊天到实时数据更新,WebSocket提供了一种高效的解决方案。本文将详细讲解如何在Java中使用WebSocket进行实时通信,涵盖基本的WebS......
  • 零基础STM32单片机编程入门(二十) 华邦W25Q32 SPI FLASH实战含源码
    文章目录一.概要二.W25Q32SPIFLASH主要参数三.W25Q32SPIFLASH芯片介绍1.W25Q32芯片内部框图2.W25Q32芯片指令表格3.W25Q32芯片通讯时序四.W25Q32SPIFLASH读写实验五.CubeMX工程源代码下载六.小结一.概要FLASH是一种存储芯片,通过程序可以修改数据,即平时所......
  • Linux多线程C/C++
    文章目录前言一、线程1.线程的使用2.线程相关函数1.pthread_create()线程创建函数2.pthread_join()线程回收函数3.pthread_exit()线程退出函数4.pthread_detach()线程分离函数二、线程的同步与互斥1.互斥锁(Mutex)2.读写锁(Read-WriteLock)3.条件变量(ConditionVa......
  • c++11(3): 类型推导与智能指针
    41.两个右尖括号>在模板中不再被判定为右移,需要右移需要加圆括号()42.auto类型推导,编译时推导inta=1;autob=a;//b的类型为int1):auto不能作函数形参类型2):auto不能对结构体中的肥静态成员进行推导3):auto不能声明数组4):auto不能在实例化模板时作为......
  • SpringBoot 配置文件详解:properties 和 yml
    目录一、配置文件的作用二、配置文件的格式三、properties配置文件说明 3.1 properties基本语法3.2读取配置文件四、yml配置文件说明4.1yml基本语法4.2yml读取文件4.3yml使用进阶4.3.1配置对象4.3.2配置集合4.3.3配置Map一、配置文件的作用配置文......
  • C++ 插入排序
    【预告】        这几次将讲讲排序(从简单开始),废话不多说,直接切入正题【关于插入排序】【定义】    定义:插入排序是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入【时间复杂度】 ......
  • 1328、基于51单片机光照人体检测手自动语音控制蓝牙远程控制智能台灯(程序+原理图+PCB
    毕设帮助、开题指导、技术解答(有偿)见文未  目录方案选择单片机的选择一、设计功能二、实物图单片机模块设计三、原理图四、程序源码五、PCB图六、proteus仿真资料包括:需要完整的资料可以点击下面的名片加下我,找我要资源压缩包的百度网盘下载地址及提取码。方......
  • 基于STC89C51单片机的智能热水器控制系统设计(含文档、源码与proteus仿真,以及系统详细
    本篇文章论述的是基于STC89C51单片机的智能热水器控制系统设计的详情介绍,如果对您有帮助的话,还请关注一下哦,如果有资源方面的需要可以联系我。目录摘 要原理图仿真图代码系统论文资源下载摘 要现在社会发展迅速,人们的生活水平都有所提高,各种热水器的使用早已屡......
  • Python类与面向对象编程
    大家好!今天我们将探讨Python中的类及其在面向对象编程(OOP)中的应用。面向对象编程是一种编程范式,它使用“对象”来模拟现实世界的事务,使代码更加结构化和易于维护。在这篇文章中,我们将详细了解类和实例的概念、'self'关键字的作用、魔法函数的定义以及构造函数和析构函数的用......