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.
以上就是进制转换的实例,如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!