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.逻辑日志开关