自用逻辑日志规范

文章详细介绍了C语言中指针和数组的使用,包括单指针、双指针和数组的地址打印,以及如何处理NULL值以避免段错误。特别提到了对NULL指针进行解引用操作的风险,并给出了安全的打印和处理方法。此外,还讨论了char*a和chara[]的区别以及内存分配的不同。
摘要由CSDN通过智能技术生成

1.说明

1.结构体(打印地址)

GCISvc *svchp

        0x%012lX --- svchp


GCIEnv **envhp

        0x%012lX --- envhp


GCICallbackOutBind ocbfp

        0x%012lX --- ocbfp


直接用变量名即可。

Note:

如果使用:*envhp,**envhp,将会出现问题:

        当传入的GCIEnv **envhp为NULL时,由于双指针envhp为空,所以对envhp的取值(即*envhp)会造成core dumped,**envhp更不行。

2.数组(打印地址)

char bvnl[ ]

        0x%012lX --- bvnl


char *bvnp[ ]

        0x%012lX --- bvnp


int a[ ]

        0x%012lX --- a


直接用变量名即可。

3.数字与字符串(打印值)

signed int a

        %d --- *a


unsigned int b

        %u --- *b


size_t c

        %zu --- *c(%d也可以,不会有问题)


CONST GCItext *poolName(const char *)

        %s --- poolName

Note:

当char *a和int *a类型传入为NULL时,gci_trace()需要对此变量进行处理,否则在取值时会出现段错误。

1.(poolName == NULL) ? (GCIText *)"null" : poolName

2.(retTagInfo_len == NULL) ? 0 : *retTagInfo_len

此时整型指针的处理会有问题,如果其值为0,会有歧义,到底是正常的0还是空指针赋0,

故只能退而求其次,输出整形指针的地址:

(retTagInfo_len == NULL) ? (int *)NULLSTR : retTagInfo_len

char* a 和 char a[] 

char* a 和 char a[ ] 都是用于表示字符数组的方式,但它们之间有一些重要的区别。

1. char* a:这是一个指针变量,用于指向字符的内存地址。它可以用来表示一个字符数组,也可以指向其他字符数组。例如:

           char* a = "Hello";

   这里 a 是一个指向字符串常量 "Hello" 的指针。可以通过解引用 a 来访问每个字符:

           char c = *a;


2. char a[ ]:这是一个字符数组,用于存储一组字符。它是一个在内存中连续分配的字符序列,例如:

           char a[ ] = "World";

   这里 a 是一个字符数组,存储了字符串常量 "World"。通过索引来访问数组元素:

           char c = a[0];


主要区别:

1.内存分配方式:char* a 是一个指针变量,它可以指向任何字符数组,包括字符串常量。它需要在运行时分配内存。而 char a[ ] 是一个字符数组,它在编译时就分配了固定大小的内存。

2.大小分配:char* a 在声明时没有指定数组的大小,所以可以动态地分配内存,可以根据需要动态调整大小。而 char a[ ] 声明时指定了数组的大小,所以大小是固定的。

   需要注意的是,char* a 也可以用于动态分配内存,例如使用 malloc 函数来分配内存空间。不过,在这种情况下,需要手动管理内存的分配和释放,以避免内存泄漏或悬挂指针等问题。


总结:char* a 是一个指向字符的指针变量,可以指向任何字符数组;而 char a[] 是一个用于存储字符的固定大小数组。

2.补充

1.

输出普通变量的地址,可以写为printf("%x",&变量)

若变量为指针时,       则应写为printf("%x",指针)

若变量为双指针,       则应写为printf("%x",*指针)


2.

%d 有符号10进制整数(signed int)

%u 无符号10进制整数(unsigned int)

%X 无符号的16进制数字,并以大写ABCDEF表示

%p与%X都可以打印地址,本示例使用十六进制大写12位地址:0x%012lX


3.

char a[ ] 声明的是一个字符数组,存储一串字符,a可以被视为一个指向字符的指针。

(等价于char*)
char* a[ ]则声明了一个指针数组,即一个由指向字符的指针组成的数组。

(等价于char**)

输出两者的地址:

        char *a [ ] = {"China","America","German"};        printf("%p \n",a);

        char  a [ ] = "Hello World"; printf("地址:");            printf("%p \n",a);


4.

输出dvoid,void**类型的变量,直接写变量名就行,否则会dumped。

3.举例

1.输出形式

"<GCIStmtGetBindInfo>\n\tGCIStmt*     \t0x%012lX\n\tGCIError*    \t0x%012lX\n\tub4
     \t%d\n\tsb4*     \t%d\n\tGCIBind*      \t0x%012lX"    //(一部分)

 每个空部分为5个空格,以规范输出格式

2.调用逻辑日志函数

if(fTrace)
{
    gci_trace(rc ,TRACE_ENTER, SQL_GCISESSIONGET ,envhp, errhp, *svchp, authhp,
    (poolName == NULL) ? (GCIText *)NULLSTR : poolName, poolName_len,
    (tagInfo == NULL) ? (const GCIText *)NULLSTR : tagInfo, tagInfo_len,
     retTagInfo, (retTagInfo_len == NULL) ? 0 : *retTagInfo_len,
    (found == NULL) ? 0 : *found, mode);
}

Note:

        *取值,&取地址

        在尝试让 printf 函数输出空指针时,printf 解引用空指针并尝试访问地址0处的内存,这是非法的操作,会出现段错误。


1.GCIEnv *envhp,envhp为GCIEnv类型的单指针变量,也是此指针指向的普通变量地址。所以输出普通变量的地址,即printf("%lx",envhp),本项目中使用0x%012lX,以规范输出格式。


2.GCIEnv **envhp,envhp为GCIEnv类型的双指针变量其对应的普通变量地址*envhp(即对双指针变量取值,得到单指针),所以当**envhp为NULL时,取*envhp会造成段错误,故输出普通变量指针地址就行,也是printf("%lx",envhp)。


3.GCIText *poolName(即char *poolName),等价于char poolName[ ],其地址就是poolName,输出poolName的值,用printf("%s",poolName),当poolName为NULL时,printf("%s",poolName)会造成段错误,因为取指针poolName得到%s是对其进行解引用,而解引用空指针是非法的。故要对其进行判断:

        (poolName == NULL) ? (GCIText *)"null" : poolName


4.ub4 *retTagInfo_len,输出普通变量的值要用printf("%d",*retTagInfo_len),当retTagInfo_len为NULL时,取*retTagInfo_len会造成段错误,故要对其进行判断:

        (retTagInfo_len == NULL) ? 0 : *retTagInfo_len

3.逻辑日志开关

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值