g one test

本文详细解析了位结构体的概念、定义方法及其在内存中的存储原理,并通过实例演示如何理解和运用位结构体。
写出下列程序在X86上的运行结果。
struct mybitfields
{
unsigned short a : 4;
unsigned short b : 5;
unsigned short c : 7;
}test;

void main(void) 
{
int i;
test.a=2;
test.b=3;
test.c=0;
i=*((short *)&test);
printf("%d ",i);
}
 
这个题的为难之处呢,就在于前面定义结构体里面用到的冒号,如果你能理解这个符号的含义,那么问题就很好解决了。这里的冒号相当于分配几位空间,也即在定义结构体的时候,分配的成员a 4位的空间, b 5位,c 7位,一共是16位,正好两个字节。下面画一个简单的示意:
变量名  位数
test      15 14 13 12 11 10 9 |8 7 6 5 4 |3 2 1 0
test.a                                                              |0 0  1 0
test.b                                            |0 0 0 1 1 |
test.c    0 0 |                    |
在执行i=*((short *)&test); 时,取从地址&test开始两个字节(short占两个字节)的内容转化为short型数据,即为0x0032,再转为int型为0x00000032,即50。输出的结果就是50。当然,这里还涉及到字节及位的存储顺序问题,后面再说。
           
前面定义的结构体被称为位结构体。所谓位结构体,是一种特殊的结构体,在需要按位访问字节或字的一个或多个位时,位结构体比按位操作要更方便一些。
位结构体的定义方式如下:
struct [位结构体名]{
数据类型 变量名:整数常数;
...
}位结构变量;
说明:
1)这里的数据类型只能为int型(包括signed和unsigned);
2)整数常数必须为0~15之间的整数,当该常数为1时,数据类型为unsigned(显然嘛,只有一位,咋表示signed?光一符号?没意义呀);
3)按数据类型变量名:整数常数;方式定义的结构成员称为位结构成员,好像也叫位域,在一个位结构体中,可以同时包含位结构成员及普通的结构成员;
4)位结构成员不能是指针或数据,但结构变量可以是指针或数据;
5)位结构体所占用的位数由各个位结构成员的位数总各决定。如在前面定义的结构体中,一共占用4+5+7=16位,两个字节。另外我们看到,在定义位结构成员时,必须指定数据类型,这个数据类型在位结构体占用多少内存时也起到不少的作用。举个例子:
struct mybitfieldA{
char a:4;
char b:3;
}testA;
 
struct mybitfieldB{
short  a:4;
short  b:3;
}testB;
这里,testA占用一个字节,而testB占用两个字节。知道原因了吧。在testA中,是以char来定义位域的,char是一个字节的,因此,位域占用的单位也按字节做单位,也即,如果不满一个字节的话按一个字节算(未定义的位按零处理)。而在testB中,short为两个字节,所以了,不满两个字节的都按两个字节算(未定义位按零处理)
 
关于位结构体在内存中的存储问题
Kevin's Theory #2: In a C structure that contains bit fields, if field A is defined in front of field B, then field A always occupies a lower bit address than field B. (来自 http://www.linuxforum.net/forum/showflat.php?Cat=&Board=linuxk&Number=638637&page=0&view=collapsed&sb=5&o=all&fpart=all
说的是,在C结构体中,如果一个位域A在另一个位域B之前定义,那么位域A将存储在比B小的位地址中。
如果一个位域有多个位时,各个位的排列顺序通常是按CPU的端模式(Endianess)来进行的,即在大端模式(big endian)下,高有效位在低位地址,小端模式则相反。
补充说明一个关于位域与普通结构成员一起使用的问题
先看一个例子
struct mybitfield{
char a:4;
char b:3;
char aa;
char c:1;}test;
这种情况下,test应该占几个字节呢?2个(4+3+1=8占一个字节,aa占一个)还是3个(4+3不足补一位,占一个字节,aa占一个字节,c占一个字节)?
写个小程序验证一下:

int main(int argc, char* argv[])
{
 int i;
 test.a = 1;
 test.b = 1;
 test.aa = 1;
 test.c = 1;

 i=*((short *)&test);
 printf("%d \n",i);

 return 0;
}

输出结果是273,化为十六进制数0x111,可见是按三个字节来处理了(如果按两个字节处理的话,cba组成一个字节,是10010001(十六进制0x91)再加上aa,那就应该是0x191了)

举这个例子是为了说明一下,定义位域的话,最好是把所以有位域放在一起,这样可以节省空间(如果把c和aa换一下位置,那test就只占两个字节了)。另外也是为了强调一下位结构体的内存分配方式,按定义的先后顺序来分配,而位域(或成员)内的字节顺序则按照CPU的位顺序来进行(一般与CPU的端模式对应)。
分析以下触摸屏画线代码,有无错误 static void draw_line(lv_point_precise_t p1, lv_point_precise_t p2, lv_event_t * e) { lv_obj_t * obj = lv_event_get_user_data(e); if (NULL == obj) { TP_LVGL_ERROR("draw_line obj is NULL !"); return; } lv_area_t area; lv_obj_get_coords(obj, &area); int32_t x_ofs = area.x1 - lv_obj_get_scroll_x(obj); int32_t y_ofs = area.y1 - lv_obj_get_scroll_y(obj); lv_draw_line_dsc_t line_dsc; lv_draw_line_dsc_init(&line_dsc); lv_obj_init_draw_line_dsc(obj, LV_PART_MAIN, &line_dsc); int32_t w = lv_obj_get_width(obj); int32_t h = lv_obj_get_height(obj); line_dsc.p1.x = resolve_point_coord(p1.x, w) + x_ofs; line_dsc.p1.y = resolve_point_coord(p1.y, h); line_dsc.p2.x = resolve_point_coord(p2.x, w) + x_ofs; line_dsc.p2.y = resolve_point_coord(p2.y, h); line_dsc.p1.y = line_dsc.p1.y + y_ofs; line_dsc.p2.y = line_dsc.p2.y + y_ofs; /*Draw the rounding only on the end points after the first line*/ line_dsc.round_start = 0; lv_canvas_init_layer(g_canvas, &g_layer); lv_draw_line(&g_layer, &line_dsc); lv_canvas_finish_layer(g_canvas, &g_layer); } static void draw_event_cb(lv_event_t * e) { lv_point_t point = {0}; lv_event_code_t code = lv_event_get_code(e); lv_obj_t * cont = lv_event_get_target(e); lv_obj_t * ts_cont = lv_event_get_user_data(e); if (ts_cont == NULL) { TP_LVGL_ERROR("user data is invalid"); return; } if(code == LV_EVENT_PRESSED) { if (g_test_draw_data.line_cnt >= LINE_NUM) { TP_LVGL_ERROR("Only supports drawing up to %d lines", LINE_NUM); return; } lv_indev_get_point(lv_indev_get_act(), &point); TP_LVGL_ERROR("LV_EVENT_PRESSED--x:%d, y:%d", point.x, point.y); lv_obj_t *line = lv_line_create(ts_cont); lv_obj_add_style(line, &style_line, 0); g_test_draw_data.line_cnt++; int line_idx = g_test_draw_data.line_cnt - 1; g_test_draw_data.line[line_idx] = line; g_test_draw_data.ts_line[line_idx].ts_points[0].x = point.x; g_test_draw_data.ts_line[line_idx].ts_points[0].y = (int)(point.y - LV_VER_RES * 0.1); g_test_draw_data.ts_line[line_idx].point_cnt = 1; lv_line_set_points(line, g_test_draw_data.ts_line[line_idx].ts_points, 1); // lv_obj_t *line = lv_line_create(ts_cont); // g_test_draw_data.line[g_test_draw_data.line_cnt++] = line; // lv_obj_add_style(line, &style_line, 0); // int line_idx = g_test_draw_data.line_cnt - 1; // g_test_draw_data.ts_line[line_idx].ts_points[0].x = point.x; // g_test_draw_data.ts_line[line_idx].ts_points[0].y = (int)(point.y - LV_VER_RES * 0.1); // g_test_draw_data.ts_line[line_idx].point_cnt = 1; // lv_line_set_points_mutable(line, g_test_draw_data.ts_line[line_idx].ts_points, 1); } else if (code == LV_EVENT_PRESSING) { if (g_test_draw_data.line_cnt >= LINE_NUM) { TP_LVGL_ERROR("Only supports drawing up to %d lines", LINE_NUM); return; } lv_indev_get_point(lv_indev_get_act(), &point); // TP_LVGL_ERROR("LV_EVENT_PRESSING--x:%d, y:%d", point.x, point.y); int line_idx = g_test_draw_data.line_cnt - 1; // lv_obj_t *line = g_test_draw_data.line[line_idx]; // // lv_obj_add_style(line, &style_line, 0); int point_cnt = g_test_draw_data.ts_line[line_idx].point_cnt; if (point_cnt >= LINE_POINT_NUM) { TP_LVGL_ERROR("Only support %d points for one line", LINE_POINT_NUM); return; } if (point.x != g_test_draw_data.ts_line[line_idx].ts_points[line_idx].x || (int)(point.y - LV_VER_RES * 0.1) != g_test_draw_data.ts_line[line_idx].ts_points[line_idx].y) { g_test_draw_data.ts_line[line_idx].ts_points[point_cnt].x = point.x; g_test_draw_data.ts_line[line_idx].ts_points[point_cnt].y = (int)(point.y - LV_VER_RES * 0.1); g_test_draw_data.ts_line[line_idx].point_cnt++; g_test_draw_data.ts_line[line_idx].need_flush = 1; // lv_line_set_points(line, &(g_test_draw_data.ts_line[line_idx].ts_points[0]), g_test_draw_data.ts_line[line_idx].point_cnt); draw_line(g_test_draw_data.ts_line[line_idx].ts_points[point_cnt-1], g_test_draw_data.ts_line[line_idx].ts_points[point_cnt-2], e); } // int line_idx = g_test_draw_data.line_cnt - 1; // int point_cnt = g_test_draw_data.ts_line[line_idx].point_cnt; // if (point.x != g_test_draw_data.ts_line[line_idx].ts_points[line_idx].x || // (int)(point.y - LV_VER_RES * 0.1) != g_test_draw_data.ts_line[line_idx].ts_points[line_idx].y) // { // g_test_draw_data.ts_line[line_idx].ts_points[point_cnt].x = point.x; // g_test_draw_data.ts_line[line_idx].ts_points[point_cnt].y = (int)(point.y - LV_VER_RES * 0.1); // g_test_draw_data.ts_line[line_idx].point_cnt++; // lv_line_set_points_mutable(g_test_draw_data.line[g_test_draw_data.line_cnt - 1], // g_test_draw_data.ts_line[g_test_draw_data.line_cnt - 1].ts_points, // point_cnt); // } } else if (code == LV_EVENT_RELEASED) { int line_idx = g_test_draw_data.line_cnt - 1; TP_LVGL_ERROR("line%d has %d points", g_test_draw_data.line_cnt, g_test_draw_data.ts_line[line_idx].point_cnt); } } static void init_test_draw_page(lv_obj_t *page_obj) { CHECK_EQUAL_VOID(page_obj, NULL); memset(&g_test_draw_data, 0, sizeof(tp_test_draw_data_t)); lv_obj_add_style(page_obj, g_user_style[TP_STYLE_PAGE_DEF], 0); lv_obj_remove_flag(page_obj, LV_OBJ_FLAG_SCROLLABLE); lv_obj_t *nav_bar = tp_ac_header_create(page_obj, true, 0); lv_obj_set_height(nav_bar, LV_VER_RES * 0.1); tp_ac_header_set_title(nav_bar, "Draw Test"); lv_obj_add_flag(nav_bar, LV_OBJ_FLAG_EVENT_BUBBLE); TP_AC_HEADER *header = (TP_AC_HEADER *)nav_bar; lv_style_init(&style_line); lv_style_set_line_width(&style_line, 8); lv_style_set_line_color(&style_line, lv_color_white()); lv_style_set_line_rounded(&style_line, true); lv_obj_t *ts_cont = lv_obj_create(page_obj); lv_obj_set_size(ts_cont, 720, 1280 * 9 / 10); lv_obj_add_style(ts_cont, g_user_style[TP_STYLE_PAGE_DEF], 0); lv_obj_set_style_bg_color(ts_cont, lv_palette_lighten(LV_PALETTE_GREY, 1), 0); lv_obj_align_to(ts_cont, nav_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 0); g_canvas = lv_canvas_create(ts_cont); lv_obj_add_event_cb(ts_cont, draw_event_cb, LV_EVENT_ALL, ts_cont); lv_obj_add_event_cb(header->back_btn, draw_back_cb, LV_EVENT_CLICKED, page_obj); } static void open_test_draw_page_handle(lv_obj_t *page_obj) { CHECK_EQUAL_VOID(page_obj, NULL); lv_obj_remove_flag(page_obj, LV_OBJ_FLAG_HIDDEN); lv_obj_move_foreground(page_obj); /* create canvas */ g_canvas_draw_buf = lv_draw_buf_create(720, 1280 * 9 / 10, LV_COLOR_FORMAT_ARGB8888, LV_STRIDE_AUTO); lv_canvas_set_draw_buf(g_canvas, g_canvas_draw_buf); lv_canvas_fill_bg(g_canvas, lv_palette_lighten(LV_PALETTE_GREY, 1), LV_OPA_COVER); lv_obj_center(g_canvas); // flush_timer = lv_timer_create(set_line_point_timer, 100, NULL); } static void close_test_draw_page_handle(lv_obj_t *page_obj) { CHECK_EQUAL_VOID(page_obj, NULL); lv_obj_add_flag(page_obj, LV_OBJ_FLAG_HIDDEN); // lv_image_cache_drop(g_canvas_draw_buf); lv_draw_buf_destroy(g_canvas_draw_buf); // lv_timer_del(flush_timer); }
最新发布
11-14
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值