今天码代码的时候,出现了一个诡异的问题:
首先:函数 pkt_analyzer 返回了一个
PktUnit类型的指针。我先把端点跑到puu赋值后的下一句,查看puu里面的内容,发现是正确的: payload_len = 7,pkt_len =
35
接着我再向下跑一步,发现puu内容就不对了: payload_len = 1514280713 ;pkt_len = 17 整个就不对了……
找了一个多小时,没发现问题出在哪儿!后来突然想到,可能是函数返回的时候出的问题,不能光看函数的立即返回结果!
果然,这是一个属于:使用指向局部变量的指针作为函数返回值的例子!
pointer * Func{
return pointer = &
iTemp;
}
这样做会造成非常严重的后果!!!!
千万不要企图返回局变量堆栈上的指针,返回局部栈上的指针,你的指针就指向了该局部变量iTemp的地址,由于局部栈会在函数返回的时刻清栈,然而你的指针所指向的地址还是不变的。也就是说
pointer还是指向iTemp原来的那块内存,但是接着执行下来,那块内存的内容完全是不确定的!所以,导致你下次使用 函数返回指针 ret_pointer =
Func(); ret_pointer的内容完全不确定,会产生灾难性后果!!
先给出问题代码:
#include "pkt_analyzer.h"
#include "stdio.h"
#include "string.h"
#include "malloc.h"extern PktUnit *pkt_analyzer(char *rx_buffer, int rx_len);
int main()
{
int i = 0;
int payload_len = 0;
u_int8 *my_payload = (u_int8 *)malloc(sizeof(u_int8));PktUnit *ppu = 0;
char in_buffer[PKT_HDEADER_LEN + 7] = {0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0e,0x05,0x0d,0x2e,0x23,0x01,0xc2,0x0e,0x0be,0xff,0x03,0x04,0x05,0x06,0x07};
ppu = pkt_analyzer(in_buffer,sizeof(in_buffer));
printf("payload_len = %d\n",ppu->payload_len);
printf("pkt_len = %d \n",ppu->pkt_len);
printf("timestampe = %ul",ppu->pkt_hdr.timestamp);memcpy(my_payload, ppu->payload,sizeof(u_int8)*ppu->payload_len);
for(i=0; i< ppu->payload_len ;i++){
printf("%x\n", *my_payload++);
}free(my_payload);
return 0;
}
/*
* recv_pkt_analyzer.c
*
* Created on: 2014-5-7
* Author: fang ying
*//* @Function Description: Perform packet analysis
*
* @param
* @param
* @return
*/#include "pkt_analyzer.h"
#include "stdlib.h"
#include "string.h"#ifndef NULL
#define NULL 0
#endif#define MakeDoubleWord(a,b,c,d,e,f,g,h) (((u_int64)(a & 0xff) << 56 )|((u_int64)(b & 0xff) << 48)|\
((u_int64)(c & 0xff) << 40 )|((u_int64)(d & 0xff) << 32)| ((u_int64)(e & 0xff) << 24 )|((u_int64)(f & 0xff) << 16)| ((u_int64)(g & 0xff) << 8 )|((u_int64)(h & 0xff) << 0 ))#define MakeWord(a,b,c,d) (((u_int32)(a & 0xff) << 24 )|((u_int32)(b & 0xff) << 16)|\
((u_int32)(c & 0xff) << 8 ) |((u_int32)(d & 0xff) << 0))PktUnit *pkt_analyzer(char *rx_buffer, int rx_len){
u_int32 get_class_id = 0;
u_int32 get_cmd_field = 0;
u_int64 get_timestamp = 0;
u_int32 get_parameter = 0;
u_int32 get_pkt_payload = 0;PktUnit packet_rx;
PktUnit *pkt_unit = NULL;/* first check the validity of rx buffer */
if(rx_buffer == NULL || rx_len <= 0){
return NULL;
}get_class_id = MakeWord(rx_buffer[0],rx_buffer[1],rx_buffer[2],rx_buffer[3]);
/* get the class identification of the rx packet */
switch(get_class_id){
case CMD_DATA:
packet_rx.pkt_hdr.class_id = CMD_DATA;
break;
case SHORT_MSG:
packet_rx.pkt_hdr.class_id = SHORT_MSG;
break;
case LONG_MSG:
packet_rx.pkt_hdr.class_id = LONG_MSG;
break;
case EXTDATA_MSG:
packet_rx.pkt_hdr.class_id = EXTDATA_MSG;
break;
case CMD_EXCHANGE:
packet_rx.pkt_hdr.class_id = CMD_EXCHANGE;
break;
default:
return NULL;
}/* check direction */
get_cmd_field = MakeWord(rx_buffer[8],rx_buffer[9],rx_buffer[10],rx_buffer[11]);
if(get_cmd_field != MASTER_2_TASK){
return NULL;
}else{
// fill the cmd field
packet_rx.pkt_hdr.cmd_field = get_cmd_field;
}/* get parameter field */
get_parameter = MakeWord(rx_buffer[12],rx_buffer[13],rx_buffer[14],rx_buffer[15]);
packet_rx.pkt_hdr.para_field = get_parameter;/* get timestamp information */
get_timestamp = MakeDoubleWord(rx_buffer[20],rx_buffer[21],rx_buffer[22],rx_buffer[23],
rx_buffer[24],rx_buffer[25],rx_buffer[26],rx_buffer[27]);
packet_rx.pkt_hdr.timestamp = get_timestamp;/* get packet length */
packet_rx.pkt_len = rx_len;/* analysis packet according to class id */
if(get_class_id == CMD_DATA){
packet_rx.payload_len = CMD_DATA_PAYLOAD_LEN;
}if(get_class_id == SHORT_MSG){
switch(get_parameter){
case AUDIO_250MS:
packet_rx.payload_len = AUDIO_250MS_PAYLOAD_LEN;
break;
case SHORT_MSG_250MS:
packet_rx.payload_len = SHORT_MSG_250MS_PAYLOAD_LEN;
break;
case SHORT_MSG_500MS:
packet_rx.payload_len = SHORT_MSG_500MS_PAYLOAD_LEN;
break;
case KEYBOARD_250MS:
packet_rx.payload_len = KEYBOARD_250MS_PAYLOAD_LEN;
break;
case KEYBOARD_500MS:
packet_rx.payload_len = KEYBOARD_500MS_PAYLOAD_LEN;
break;
default:
return NULL;
}
}if(get_class_id == LONG_MSG){
switch(get_parameter){
case LONG_MSG_500MS:
packet_rx.payload_len = LONG_MSG_500MS_PAYLOAD_LEN;
break;
case LONG_MSG_750MS:
packet_rx.payload_len = LONG_MSG_750MS_PAYLOAD_LEN;
break;
default:
return NULL;
}
}if(get_class_id == EXTDATA_MSG){
switch(get_parameter){
case EXT_DATA_1P2K:
packet_rx.payload_len = EXT_DATA_1P2K_PAYLOAD_LEN;
break;
case EXT_DATA_2P4K:
packet_rx.payload_len = EXT_DATA_2P4K_PAYLOAD_LEN;
break;
case EXT_DATA_4P8K:
packet_rx.payload_len = EXT_DATA_4P8K_PAYLOAD_LEN;
break;
case EXT_DATA_9P6K:
packet_rx.payload_len = EXT_DATA_9P6K_PAYLOAD_LEN;
break;
case EXT_DATA_19P2K:
packet_rx.payload_len = EXT_DATA_19P2K_PAYLOAD_LEN;
break;
case EXT_DATA_25P6K:
packet_rx.payload_len = EXT_DATA_25P6K_PAYLOAD_LEN;
break;
case EXT_DATA_38P4K:
packet_rx.payload_len = EXT_DATA_38P4K_PAYLOAD_LEN;
break;
default:
return NULL;
}
}if(get_class_id == CMD_EXCHANGE){
switch(get_parameter){
case SIGNALING_400MS_RECV_MODE:
break;
case AUDIO_250MS_RECV_MODE:
break;
case SHORT_MSG_250MS_RECV_MODE:
break;
case SHORT_MSG_500MS_RECV_MODE:
break;
case KEYBOARD_250MS_RECV_MODE:
break;
case KEYBOARD_500MS_RECV_MODE:
break;
case LONG_MSG_500MS_RECV_MODE:
break;
case LONG_MSG_750MS_RECV_MODE:
break;
case EXT_DATA_1P2K_RECV_MODE:
break;
case EXT_DATA_2P4K_RECV_MODE:
break;
case EXT_DATA_4P8K_RECV_MODE:
break;
case EXT_DATA_9P6K_RECV_MODE:
break;
case EXT_DATA_19P2K_RECV_MODE:
break;
case EXT_DATA_25P6K_RECV_MODE:
break;
case EXT_DATA_38P4K_RECV_MODE:
break;
default:
return NULL;
}
}/* get payload */
packet_rx.payload = (int_8 *)malloc(sizeof(u_int8));
//packet_rx.payload = &rx_buffer[PKT_HDEADER_LEN];
memcpy(packet_rx.payload,&rx_buffer[PKT_HDEADER_LEN],sizeof(u_int8)*packet_rx.payload_len);pkt_unit = &packet_rx;
return (pkt_unit);
}
/*
* pkt_analyzer.h
*
* Created on: 2014-5-7
* Author: fang ying
*/#ifndef _PKT_ANALYZER_H_
#define _PKT_ANALYZER_H_/* type defination */
typedef char int_8;
typedef unsigned char u_int8;
typedef unsigned short u_int16;
typedef unsigned int u_int32;
typedef unsigned long long u_int64;typedef struct PktHeader_t{
u_int32 class_id; /* class identification unique number*/
u_int32 board_id; /* board identification */
u_int32 cmd_field; /* command field */
u_int32 para_field; /* parameter field */
u_int64 freq_info; /* frequency information */
u_int32 channel_SNR; /* SNR of the channel */
u_int64 timestamp; /* timestamp */}PktHeader;
typedef struct PktUnit_t{
PktHeader pkt_hdr; /* packet header */
int_8 *payload; /* data payload */
u_int32 payload_len; /* packet payload length */
u_int32 pkt_len; /* packet total length */
}PktUnit;/* constriant definations */
#define PKT_HDEADER_LEN 28/* class identification */
#define CMD_DATA 0x1 /* command data unit */
#define SHORT_MSG 0x2 /* short message data unit */
#define LONG_MSG 0x3 /* long message data unit */
#define EXTDATA_MSG 0x4 /* extra data frame unit */
#define CMD_EXCHANGE 0x5 /* command exchange unit *//* board identification */
#define MASTER_BOARD 0x0
#define TASK_BOARD 0x1/* command field of command data unit */
#define MASTER_2_TASK 0x1
#define TASK_2_MASTER 0x2/******************** command data unit header explain **********************/
/* parameter field of command data unit */
#define FREQUENCY_PAYLOAD_INFO 0x1
#define FREQUENCY_INFO_ONLY 0x2
#define PAYLOAD_INFO_ONLY 0x3
#define RESERVED 0x4#define SYN_CHECKED 0x1
#define RECEIVE_COMPLETE 0x2
#define EARLY_TX_SUCESS 0x3
#define EARLY_TX_FAILED 0x4/******************** short and long message data unit header explain ****************/
/* parameter field of short message interact unit */
#define AUDIO_250MS 0x1
#define SHORT_MSG_250MS 0x2
#define SHORT_MSG_500MS 0x3
#define KEYBOARD_250MS 0x4
#define KEYBOARD_500MS 0x5
#define LONG_MSG_500MS 0x6
#define LONG_MSG_750MS 0x7
#define EXT_DATA_1P2K 0x8
#define EXT_DATA_2P4K 0x9
#define EXT_DATA_4P8K 0x10
#define EXT_DATA_9P6K 0x11
#define EXT_DATA_19P2K 0x12
#define EXT_DATA_25P6K 0x13
#define EXT_DATA_38P4K 0x14/* length constraints of message */
#define CMD_DATA_PAYLOAD_LEN 7
#define AUDIO_250MS_PAYLOAD_LEN 62
#define SHORT_MSG_250MS_PAYLOAD_LEN 94
#define SHORT_MSG_500MS_PAYLOAD_LEN 94
#define KEYBOARD_250MS_PAYLOAD_LEN 94
#define KEYBOARD_500MS_PAYLOAD_LEN 94
#define LONG_MSG_500MS_PAYLOAD_LEN 478
#define LONG_MSG_750MS_PAYLOAD_LEN 766
#define EXT_DATA_1P2K_PAYLOAD_LEN 574
#define EXT_DATA_2P4K_PAYLOAD_LEN 574
#define EXT_DATA_4P8K_PAYLOAD_LEN 574
#define EXT_DATA_9P6K_PAYLOAD_LEN 1152
#define EXT_DATA_19P2K_PAYLOAD_LEN 2304
#define EXT_DATA_25P6K_PAYLOAD_LEN 3456
#define EXT_DATA_38P4K_PAYLOAD_LEN 4608/**************** command exchange unit header explain *****************/
/* parameter field of command exchange unit */
#define SIGNALING_400MS_RECV_MODE 0x0
#define AUDIO_250MS_RECV_MODE 0x1
#define SHORT_MSG_250MS_RECV_MODE 0x2
#define SHORT_MSG_500MS_RECV_MODE 0x3
#define KEYBOARD_250MS_RECV_MODE 0x4
#define KEYBOARD_500MS_RECV_MODE 0x5
#define LONG_MSG_500MS_RECV_MODE 0x6
#define LONG_MSG_750MS_RECV_MODE 0x7
#define EXT_DATA_1P2K_RECV_MODE 0x8
#define EXT_DATA_2P4K_RECV_MODE 0x9
#define EXT_DATA_4P8K_RECV_MODE 0x10
#define EXT_DATA_9P6K_RECV_MODE 0x11
#define EXT_DATA_19P2K_RECV_MODE 0x12
#define EXT_DATA_25P6K_RECV_MODE 0x13
#define EXT_DATA_38P4K_RECV_MODE 0x14#endif /* PKT_ANALYZER_H_ */
问题出在这个地方:
这里使用了指向局部变量的指针,并作为函数的返回指针。
改正后的代码如下
/*
* recv_pkt_analyzer.c
*
* Created on: 2014-5-7
* Author: fang ying
*//* @Function Description: Perform packet analysis
*
* @param
* @param
* @return
*/#include "pkt_analyzer.h"
#include "stdlib.h"
#include "string.h"#ifndef NULL
#define NULL 0
#endif#define MakeDoubleWord(a,b,c,d,e,f,g,h) (((u_int64)(a & 0xff) << 56 )|((u_int64)(b & 0xff) << 48)|\
((u_int64)(c & 0xff) << 40 )|((u_int64)(d & 0xff) << 32)| ((u_int64)(e & 0xff) << 24 )|((u_int64)(f & 0xff) << 16)| ((u_int64)(g & 0xff) << 8 )|((u_int64)(h & 0xff) << 0 ))#define MakeWord(a,b,c,d) (((u_int32)(a & 0xff) << 24 )|((u_int32)(b & 0xff) << 16)|\
((u_int32)(c & 0xff) << 8 ) |((u_int32)(d & 0xff) << 0))PktUnit *pkt_analyzer(char *rx_buffer, int rx_len){
u_int32 get_class_id = 0;
u_int32 get_cmd_field = 0;
u_int64 get_timestamp = 0;
u_int32 get_parameter = 0;
u_int32 get_pkt_payload = 0;PktUnit *packet_rx = (PktUnit *)malloc(sizeof(PktUnit));
/* first check the validity of rx buffer */
if(rx_buffer == NULL || rx_len <= 0){
return NULL;
}get_class_id = MakeWord(rx_buffer[0],rx_buffer[1],rx_buffer[2],rx_buffer[3]);
/* get the class identification of the rx packet */
switch(get_class_id){
case CMD_DATA:
packet_rx->pkt_hdr.class_id = CMD_DATA;
break;
case SHORT_MSG:
packet_rx->pkt_hdr.class_id = SHORT_MSG;
break;
case LONG_MSG:
packet_rx->pkt_hdr.class_id = LONG_MSG;
break;
case EXTDATA_MSG:
packet_rx->pkt_hdr.class_id = EXTDATA_MSG;
break;
case CMD_EXCHANGE:
packet_rx->pkt_hdr.class_id = CMD_EXCHANGE;
break;
default:
return NULL;
}/* check direction */
get_cmd_field = MakeWord(rx_buffer[8],rx_buffer[9],rx_buffer[10],rx_buffer[11]);
if(get_cmd_field != MASTER_2_TASK){
return NULL;
}else{
// fill the cmd field
packet_rx->pkt_hdr.cmd_field = get_cmd_field;
}/* get parameter field */
get_parameter = MakeWord(rx_buffer[12],rx_buffer[13],rx_buffer[14],rx_buffer[15]);
packet_rx->pkt_hdr.para_field = get_parameter;/* get timestamp information */
get_timestamp = MakeDoubleWord(rx_buffer[20],rx_buffer[21],rx_buffer[22],rx_buffer[23],
rx_buffer[24],rx_buffer[25],rx_buffer[26],rx_buffer[27]);
packet_rx->pkt_hdr.timestamp = get_timestamp;/* get packet length */
packet_rx->pkt_len = rx_len;/* analysis packet according to class id */
if(get_class_id == CMD_DATA){
packet_rx->payload_len = CMD_DATA_PAYLOAD_LEN;
}if(get_class_id == SHORT_MSG){
switch(get_parameter){
case AUDIO_250MS:
packet_rx->payload_len = AUDIO_250MS_PAYLOAD_LEN;
break;
case SHORT_MSG_250MS:
packet_rx->payload_len = SHORT_MSG_250MS_PAYLOAD_LEN;
break;
case SHORT_MSG_500MS:
packet_rx->payload_len = SHORT_MSG_500MS_PAYLOAD_LEN;
break;
case KEYBOARD_250MS:
packet_rx->payload_len = KEYBOARD_250MS_PAYLOAD_LEN;
break;
case KEYBOARD_500MS:
packet_rx->payload_len = KEYBOARD_500MS_PAYLOAD_LEN;
break;
default:
return NULL;
}
}if(get_class_id == LONG_MSG){
switch(get_parameter){
case LONG_MSG_500MS:
packet_rx->payload_len = LONG_MSG_500MS_PAYLOAD_LEN;
break;
case LONG_MSG_750MS:
packet_rx->payload_len = LONG_MSG_750MS_PAYLOAD_LEN;
break;
default:
return NULL;
}
}if(get_class_id == EXTDATA_MSG){
switch(get_parameter){
case EXT_DATA_1P2K:
packet_rx->payload_len = EXT_DATA_1P2K_PAYLOAD_LEN;
break;
case EXT_DATA_2P4K:
packet_rx->payload_len = EXT_DATA_2P4K_PAYLOAD_LEN;
break;
case EXT_DATA_4P8K:
packet_rx->payload_len = EXT_DATA_4P8K_PAYLOAD_LEN;
break;
case EXT_DATA_9P6K:
packet_rx->payload_len = EXT_DATA_9P6K_PAYLOAD_LEN;
break;
case EXT_DATA_19P2K:
packet_rx->payload_len = EXT_DATA_19P2K_PAYLOAD_LEN;
break;
case EXT_DATA_25P6K:
packet_rx->payload_len = EXT_DATA_25P6K_PAYLOAD_LEN;
break;
case EXT_DATA_38P4K:
packet_rx->payload_len = EXT_DATA_38P4K_PAYLOAD_LEN;
break;
default:
return NULL;
}
}if(get_class_id == CMD_EXCHANGE){
switch(get_parameter){
case SIGNALING_400MS_RECV_MODE:
break;
case AUDIO_250MS_RECV_MODE:
break;
case SHORT_MSG_250MS_RECV_MODE:
break;
case SHORT_MSG_500MS_RECV_MODE:
break;
case KEYBOARD_250MS_RECV_MODE:
break;
case KEYBOARD_500MS_RECV_MODE:
break;
case LONG_MSG_500MS_RECV_MODE:
break;
case LONG_MSG_750MS_RECV_MODE:
break;
case EXT_DATA_1P2K_RECV_MODE:
break;
case EXT_DATA_2P4K_RECV_MODE:
break;
case EXT_DATA_4P8K_RECV_MODE:
break;
case EXT_DATA_9P6K_RECV_MODE:
break;
case EXT_DATA_19P2K_RECV_MODE:
break;
case EXT_DATA_25P6K_RECV_MODE:
break;
case EXT_DATA_38P4K_RECV_MODE:
break;
default:
return NULL;
}
}/* get payload */
packet_rx->payload = (int_8 *)malloc(sizeof(u_int8));
//packet_rx.payload = &rx_buffer[PKT_HDEADER_LEN];
memcpy(packet_rx->payload,&rx_buffer[PKT_HDEADER_LEN],sizeof(u_int8)*packet_rx->payload_len);
return packet_rx;
}
上面修改的地方,我定义了一个指针,并且动态申请了空间后面就对了。其思想是基于:
因为函数中的局部变量在函数调用结束后就会被释放;这句话是对的,局部变量超出其作用域后就会被释放掉
所以如果你在函数内部定义一个指针,并申请了空间;这句不怎么对,因为只查动态申请的内存都是在堆中申请,不会被释放掉
但是,如果是使用字符串指针形式,char
*str = "hello world"这个叫字符串字面常量。储存在静态区,是只读!!!!的所以可以返回
#include<stdio.h>char *returnstr()
{
char *str="Hello!World!";
printf("In returnstr, addr of str:\t%p\n", str);
return str; //"Hello!world!\n";
}
int main()
{
char *str=returnstr();
printf("In main, addr of str:\t%p\n", str);
printf("%s\n", str);
return 0;
}
函数中的变量存储空间是在栈上分配的,函数结束时自动释放,所以不能返回这样的变量,即使你返回了,就像7楼所说的,也得到了正确的值,请不要高兴,这是因为那块内存还没有被占用,值还没有改变,所以你得到了正确的值,有一种情况是可以返回局部指针的,就是在堆上动态分配存储空间,这些空间在函数结束时不会自动释放,但是需要自己释放,所以得记住,要是忘记了就漏掉了。
切勿使用:指向局部变量的指针作为函数的返回指针!