C语言实现进制转换函数的实例详解
C语言实现进制转换函数的实例详解
前言:
写一个二进制,八进制,十六进制转换为十进制的函数
要求:
- 函数有两个参数,参数(1)是要转换为十进制的进制数,参数(2)是标示参数(1)是什么进制(2,8,16标示二进制,八进制,十六进制)。
- 要有报错信息,比如参数是1012,但参数(2)是2,显然是进制数表示有错误。
系统表pg_proc存储关于函数的信息
内部函数在编译之前需要先定义在pg_proc.h中,src/include/catalog/pg_proc.h
CATALOG(pg_proc,1255)BKI_BOOTSTRAPBKI_ROWTYPE_OID(81)BKI_SCHEMA_MACRO { NameDataproname;/*procedurename*//*函数名,sql中select函数名();*/ Oidpronamespace;/*OIDofnamespacecontainingthisproc*//*模式OID*/ Oidproowner;/*procedureowner*//*用户OID*/ Oidprolang;/*OIDofpg_languageentry*/ float4procost;/*estimatedexecutioncost*//*估计执行成本*/ float4prorows;/*estimated#ofrowsout(ifproretset)*//*结果行估计数*/ Oidprovariadic;/*elementtypeofvariadicarray,or0*/ regprocprotransform;/*transformscallstoitduringplanning*/ boolproisagg;/*isitanaggregate?*//*是否为聚集函数*/ boolproiswindow;/*isitawindowfunction?*//*是否为窗口函数*/ boolprosecdef;/*securitydefiner*//*函数是一个安全定义器,也就是一个“setuid"函数*/ boolproleakproof;/*isitaleak-prooffunction?*//*有无其他影响*/ boolproisstrict;/*strictwithrespecttoNULLs?*//*遇到NULL值是否直接返回NULL*/ boolproretset;/*returnsaset?*//*函数返回一个集合*/ charprovolatile;/*seePROVOLATILE_categoriesbelow*/ int16pronargs;/*numberofarguments*//*参数个数*/ int16pronargdefaults;/*numberofargumentswithdefaults*//*默认参数的个数*/ Oidprorettype;/*OIDofresulttype*//*返回参数类型OID*/ /* *variable-lengthfieldsstarthere,butweallowdirectaccessto *proargtypes */ oidvectorproargtypes;/*parametertypes(excludesOUTparams)*//*存放函数参数类型的数组*/ #ifdefCATALOG_VARLEN Oidproallargtypes[1];/*allparamtypes(NULLifINonly)*/ charproargmodes[1];/*parametermodes(NULLifINonly)*/ textproargnames[1];/*parameternames(NULLifnonames)*/ pg_node_treeproargdefaults;/*listofexpressiontreesforargument *defaults(NULLifnone)*/ Oidprotrftypes[1];/*typesforwhichtoapplytransforms*/ textprosrcBKI_FORCE_NOT_NULL;/*proceduresourcetext*//*函数处理器如何调用函数,实现函数的函数名*/ textprobin;/*secondaryprocedureinfo(canbeNULL)*/ textproconfig[1];/*procedure-localGUCsettings*/ aclitemproacl[1];/*accesspermissions*/ #endif }FormData_pg_proc;
在proc.h添加函数定义:
/*myfunc*/ DATA(insertOID=6663(x_to_decPGNSPPGUID121000fffftfi2023"2523"_null__null__null__null__null_x_to_dec_null__null__null_)); DESCR("x_to_dec."); OID=6663/*OID唯一,不能与其他定义OID重复*/ x_to_dec/*sql中selectx_to_dec();*/ 2023"2523"/*传递两个参数;默认0;返回值类型OID=23;参数1类型OID=25,参数2类型OID=23*/ x_to_dec/*自定义函数名*/
这里的传递参数类型和返回值类型都用的了OID
系统表pg_type存储数据类型的信息
postgres=#selectoid,typnamefrompg_typewheretypname='text'ortypname='int4'; oid|typname -----+--------- 23|int4 25|text (2rows)
在src/backend/utils/adt/myfuncs.c实现自定义的函数
首先创建函数的整体部分:
Datum/*Datum类型是PG系统函数大量引用的类型,其定义为:typedefuintptr_cDatum*/ x_to_dec(PG_FUNCTION_ARGS)/*函数名;参数*/ { /*获取参数*/ text*arg1=PG_GETARG_TEXT_P(0); int32arg2=PG_GETARG_INT32(1); /**实现功能**/ /*返回*/ PG_RETURN_INT32(sum); }
这里的PG_GETARG_XXXX()和PG_RETURN_XXXXX()在src/include/fmgr.h
知道了如何获取参数以及返回返回值,接下来是具体的实现:
Datumx_to_dec(PG_FUNCTION_ARGS) { intn=0,i=0,sum=0,t=0; text*arg1=PG_GETARG_TEXT_P(0); int32arg2=PG_GETARG_INT32(1); char*str=text_to_cstring(arg1); n=strlen(str); switch(arg2) { case2: for(i=n-1;i>=0;i--) { if((str[i]-'0')!=1&&(str[i]-'0')!=0) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Pleaseenterthecorrectbinarynumber,suchas'110011'."))); } sum+=(str[i]-'0')*((int)pow(2,n-1-i)); } break; case8: for(i=n-1;i>=0;i--) { if(!(str[i]>='0'&&str[i]<='7')) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Pleaseenterthecorrectoctalnumber,forexample'34567'."))); } sum+=(str[i]-'0')*((int)pow(8,n-1-i)); } break; case16: for(i=n-1;i>=0;i--) { if(!(str[i]>='0'&&str[i]<='9')) { if(str[i]>='A'&&str[i]<='F') { //Uppercasetolowercase str[i]=str[i]+32; }elseif(!(str[i]>='a'&&str[i]<='f')){ ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Pleaseenterthecorrecthexadecimalnumber,forexample'9f'."))); } } if(str[i]<='9') { t=str[i]-'0'; }else{ t=str[i]-'a'+10; } sum=sum*16+t; } break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Outofrange!Thesecondparameter,pleaseenter:2,4,16."))); } PG_RETURN_INT32(sum); }
其中用到了text_to_cstring(arg1),类型转换的相关函数定义在src/backend/utils/adt/varlena.c
/* *text_to_cstring * *Createapalloc'd,null-terminatedCstringfromatextvalue. * *Wesupportbeingpassedacompressedortoastedtextvalue. *Thisisabitbogussincesuchvaluesshouldn'treallybereferredtoas *"text*",butitseemsusefulforrobustness.Ifwedidn'thandlethat *casehere,we'dneedanotherroutinethatdid,anyway. */ char* text_to_cstring(consttext*t) { /*mustcastawaytheconst,unfortunately*/ text*tunpacked=pg_detoast_datum_packed((structvarlena*)t); intlen=VARSIZE_ANY_EXHDR(tunpacked); char*result; result=(char*)palloc(len+1); memcpy(result,VARDATA_ANY(tunpacked),len); result[len]='\0'; if(tunpacked!=t) pfree(tunpacked); returnresult; }
结果:
postgres=#selectx_to_dec('111',2); x_to_dec ---------- 7 (1row) postgres=#selectx_to_dec('aA',16); x_to_dec ---------- 170 (1row) postgres=#selectx_to_dec('aA',1); ERROR:Outofrange!Thesecondparameter,pleaseenter:2,4,16.
以上就是进制转换的实例,如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!