C语言实现进制转换函数的实例详解

时间:2021-05-20

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_BOOTSTRAP BKI_ROWTYPE_OID(81) BKI_SCHEMA_MACRO{ NameData proname; Oid pronamespace; Oid proowner; Oid prolang; float4 procost; float4 prorows; Oid provariadic; regproc protransform; bool proisagg; bool proiswindow; bool prosecdef; bool proleakproof; bool proisstrict; bool proretset; char provolatile; int16 pronargs; int16 pronargdefaults; Oid prorettype; /* * variable-length fields start here, but we allow direct access to * proargtypes */ oidvector proargtypes; #ifdef CATALOG_VARLEN Oid proallargtypes[1]; char proargmodes[1]; text proargnames[1]; pg_node_tree proargdefaults;/* list of expression trees for argument * defaults (NULL if none) */ Oid protrftypes[1]; text prosrc BKI_FORCE_NOT_NULL; text probin; text proconfig[1]; aclitem proacl[1]; #endif} FormData_pg_proc;

    在 proc.h 添加函数定义:

    DATA(insert OID = 6663 ( x_to_dec PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "25 23" _null_ _null_ _null_ _null_ _null_ x_to_dec _null_ _null_ _null_ ));DESCR("x_to_dec.");OID = 6663 x_to_dec 2 0 23 "25 23" x_to_dec

    这里的传递参数类型和返回值类型都用的了 OID

    系统表 pg_type 存储数据类型的信息

    postgres=# select oid,typname from pg_type where typname = 'text' or typname = 'int4'; oid | typname -----+--------- 23 | int4 25 | text(2 rows)

    在 src/backend/utils/adt/myfuncs.c 实现自定义的函数

    首先创建函数的整体部分:

    Datum x_to_dec (PG_FUNCTION_ARGS) { text *arg1 = PG_GETARG_TEXT_P(0); int32 arg2 = PG_GETARG_INT32(1); /** 实现功能 **/ PG_RETURN_INT32(sum);}

    这里的 PG_GETARG_XXXX() 和 PG_RETURN_XXXXX() 在 src/include/fmgr.h

    知道了如何获取参数以及返回返回值,接下来是具体的实现:

    Datum x_to_dec (PG_FUNCTION_ARGS){ int n = 0, i = 0, sum = 0, t = 0; text *arg1 = PG_GETARG_TEXT_P(0); int32 arg2 = PG_GETARG_INT32(1); char *str = text_to_cstring(arg1); n = strlen(str); switch(arg2) { case 2: for(i = n - 1; i >= 0; i--) { if((str[i] - '0') != 1 && (str[i] - '0') != 0) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Please enter the correct binary number, such as '110011'."))); } sum += (str[i] - '0') * ((int)pow(2, n - 1 - i)); } break; case 8: for(i = n - 1; i >= 0; i--) { if(!(str[i] >= '0' && str[i] <= '7')) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Please enter the correct octal number, for example '34567'."))); } sum += (str[i] - '0') * ((int)pow(8, n - 1 - i)); } break; case 16: for(i = n - 1; i >= 0; i--) { if( !(str[i] >= '0' && str[i] <= '9') ) { if(str[i] >= 'A' && str[i] <= 'F') { // Uppercase to lowercase str[i] = str[i] + 32; } else if ( !(str[i] >= 'a' && str[i] <= 'f') ) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("Please enter the correct hexadecimal number, for example '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("Out of range! The second parameter, please enter: 2, 4, 16."))); } PG_RETURN_INT32(sum);}

    其中用到了text_to_cstring(arg1) ,类型转换的相关函数定义在 src/backend/utils/adt/varlena.c

    /* * text_to_cstring * * Create a palloc'd, null-terminated C string from a text value. * * We support being passed a compressed or toasted text value. * This is a bit bogus since such values shouldn't really be referred to as * "text *", but it seems useful for robustness. If we didn't handle that * case here, we'd need another routine that did, anyway. */char *text_to_cstring(const text *t){ text *tunpacked = pg_detoast_datum_packed((struct varlena *) t); int len = 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); return result;}

    结果:

    postgres=# select x_to_dec('111',2); x_to_dec ---------- 7(1 row)postgres=# select x_to_dec('aA',16); x_to_dec ---------- 170(1 row)postgres=# select x_to_dec('aA',1);ERROR: Out of range! The second parameter, please enter: 2, 4, 16.

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

    声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

    相关文章