使用offsetof对结构体指针偏移操作

题目来自于COMP20003 Tutorial 2:

Program m ing Challenge 2.2 The technology stack at Hidebound Inc. uses a subset of C w hich doesn‘t have the ‘.‘ or ‘->‘
operators, as the higher-ups heard shortcuts like this w ere useful in an activity called "code golfing" and, misunderstanding w hat
that meant, w anted to discourage all recreational activities on company time. The change improved compile times and required
resources slightly so the developer in charge of that performance w as happy to force the change on the other programmers in
the company. In this challenge, you‘ll need to replace a piece of code w hich does this using both the simple ‘->‘ and ‘.‘ operators
w ith a piece of code that instead changes the value in the struct by using value casting and pointer addition instead.
This challenge is intended to highlight that ‘.‘ and ‘->‘ are merely shortcuts to other dereference operations and though you w ill
eventually find your code is less messy w hen using them, understanding exactly w hat you are doing w ill reduce the number of
errors you make and allow you to examine code closely w hen you have something complicated that isn‘t doing exactly w hat you
think it should be. You may find reading through the (2nd) extra w orkshop material document on the LMS under the Resources
section is particularly useful for this task.
As a hint, you may find the offsetof macro useful (you can find this using the man pages). For an extra challenge, try only using
the sizeof macro, the address of operator (&) and the dereference operator (*). Note also that for the latter, a process know n as
"packing" may sometimes add holes to structs w hich are unused, though that has been carefully avoided in the struct defined
here.

 1 /*
 2 This program was written by Richard Chad Sparrow
 3 as a test case for AB-testing the hazard management
 4 system.
 5 */
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <stddef.h>
 9 struct hazard {
10     char *description;
11     void *extraData;
12     int extraDataType;
13     int id;
14     char severityClass;
15 };
16 void printHazard(struct hazard *hazard);
17 int main(int argc, char **argv){
18     struct hazard hazard1;
19     struct hazard hazard2;
20     struct hazard *lastHazard;
21     /* Hazard data setup. */
22     hazard1.description = "Brake service required.";
23     hazard1.extraData = NULL;
24     hazard1.extraDataType = 0;
25     hazard1.id = 1;
26     hazard1.severityClass = ‘A‘;
27     hazard2.description = "Unknown issue in fluid level.";
28     hazard2.extraData = NULL;
29     hazard2.extraDataType = 0;
30     hazard2.id = 2;
31     hazard2.severityClass = ‘U‘;
32     lastHazard = &hazard2;
33     printf("Hazards after setup:\n");
34     printHazard(&hazard1);
35     printHazard(&hazard2);
36     /*
37     The brake service hazard has been present for multiple
38     services, so needs to be updated to severity class ‘B‘.
39     */
40     /* Original: hazard1.severityClass = ‘B‘; */
41     /* CHANGE THE CODE HERE: */
42     hazard1.severityClass = ‘B‘;
43     printf("Hazard 1 after class B severity update:\n");
44     printHazard(&hazard1);
45     /*
46     The next hazard to be evaluted has been evaluated and
47     its severity class has been found to be quite serious,
48     class ‘D‘. As part of this issue, the id has also been
49     increased to 3 and the hazard description has been
50     changed to "Fluid leak in tank 4".
51     */
52     /* Original: lastHazard->severityClass = ‘D‘; */
53     /* CHANGE THE CODE HERE: */
54     lastHazard->severityClass = ‘D‘;
55
56     /* Original: lastHazard->description = "Fluid leak in tank 4"; */
57     /* CHANGE THE CODE HERE: */
58     lastHazard->description = "Fluid leak in tank 4";
59     printf("Hazard 2 after description and D-class update:\n");
60     printHazard(&hazard2);
61     return 0;
62 }
63 void printHazard(struct hazard *hazard){
64     printf("Hazard %d: %s [Class %c, extraDataType: %d]\n",
65     hazard->id, hazard->description, hazard->severityClass,
66     hazard->extraDataType);
67 }

即:不使用.和->替换目标代码,提示使用offsetof函数。

关于offsetof函数:http://man7.org/linux/man-pages/man3/offsetof.3.html

第一条:

1 hazard1.severityClass = ‘B‘;

替换为:

1     //*(char *)((void *)(&hazard1) + offsetof(struct hazard, severityClass)) = ‘B‘;
2     *(char *)((void *)(&hazard1) + sizeof(char *) + sizeof(void *) + sizeof(int) + sizeof(int)) = ‘B‘;

为何是(void *)(&hazard1)?

&hazard1代表了该结构体变量和其首成员的地址,直接+1或者(struct hazard *)(&hazard1)+1则直接跳出了该结构体变量的范围(如数组int a[10]:*(a+1)是a[1]一样),使用(void *)让其以字节为单位进行偏移(也可用(char *)),这样就不会跳出该结构体变量了。 源自Psrion对我提出问题的回答https://q.cnblogs.com/q/111494/

也可使用sizeof根据成员在结构体中定义的顺序进行偏移。

最后一条:

1 lastHazard->description = "Fluid leak in tank 4";

替换为:

1     //*(char **)((void *)(lastHazard) + offsetof(struct hazard, description)) = "Fluid leak in tank 4";
2     //*(char **)((void *)(lastHazard)) = "Fluid leak in tank 4";
3     *(char **)(lastHazard) = "Fluid leak in tank 4";

lastHazard为结构体指针,故不用&,description为结构体中第一个成员,即结构体变量地址同时也是该成员的地址。

答案:

 1 /*
 2 This program was written by Richard Chad Sparrow
 3 as a test case for AB-testing the hazard management
 4 system.
 5 */
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <stddef.h>
 9 struct hazard {
10     char *description;
11     void *extraData;
12     int extraDataType;
13     int id;
14     char severityClass;
15 };
16 void printHazard(struct hazard *hazard);
17 int main(int argc, char **argv){
18     struct hazard hazard1;
19     struct hazard hazard2;
20     struct hazard *lastHazard;
21     /* Hazard data setup. */
22     hazard1.description = "Brake service required.";
23     hazard1.extraData = NULL;
24     hazard1.extraDataType = 0;
25     hazard1.id = 1;
26     hazard1.severityClass = ‘A‘;
27     hazard2.description = "Unknown issue in fluid level.";
28     hazard2.extraData = NULL;
29     hazard2.extraDataType = 0;
30     hazard2.id = 2;
31     hazard2.severityClass = ‘U‘;
32     lastHazard = &hazard2;
33     printf("Hazards after setup:\n");
34     printHazard(&hazard1);
35     printHazard(&hazard2);
36     /*
37     The brake service hazard has been present for multiple
38     services, so needs to be updated to severity class ‘B‘.
39     */
40     /* Original: hazard1.severityClass = ‘B‘; */
41     /* CHANGE THE CODE HERE:
42     //hazard1.severityClass = ‘B‘;*/
43
44     //*(char *)((void *)(&hazard1) + offsetof(struct hazard, severityClass)) = ‘B‘;
45     *(char *)((void *)(&hazard1) + sizeof(char *) + sizeof(void *) + sizeof(int) + sizeof(int)) = ‘B‘;
46
47     printf("Hazard 1 after class B severity update:\n");
48     printHazard(&hazard1);
49     /*
50     The next hazard to be evaluted has been evaluated and
51     its severity class has been found to be quite serious,
52     class ‘D‘. As part of this issue, the id has also been
53     increased to 3 and the hazard description has been
54     changed to "Fluid leak in tank 4".
55     */
56     /* Original: lastHazard->severityClass = ‘D‘; */
57     /* CHANGE THE CODE HERE:
58     lastHazard->severityClass = ‘D‘;*/
59
60     *(char *)((void *)(lastHazard) + offsetof(struct hazard, severityClass)) = ‘D‘;
61
62     /* Original: lastHazard->description = "Fluid leak in tank 4"; */
63     /* CHANGE THE CODE HERE:
64     lastHazard->description = "Fluid leak in tank 4";*/
65
66     //*(char **)((void *)(lastHazard) + offsetof(struct hazard, description)) = "Fluid leak in tank 4";
67     //*(char **)((void *)(lastHazard)) = "Fluid leak in tank 4";
68     *(char **)(lastHazard) = "Fluid leak in tank 4";
69
70     printf("Hazard 2 after description and D-class update:\n");
71     printHazard(&hazard2);
72     return 0;
73 }
74 void printHazard(struct hazard *hazard){
75     printf("Hazard %d: %s [Class %c, extraDataType: %d]\n",
76     hazard->id, hazard->description, hazard->severityClass,
77     hazard->extraDataType);
78 }

原文地址:https://www.cnblogs.com/Will-zyq/p/10049052.html

时间: 2024-10-31 06:51:46

使用offsetof对结构体指针偏移操作的相关文章

ctypes 操作 python 与 c++ dll 互传结构体指针

CMakeLists.txt # project(工程名) project(blog-3123958139-1) # add_library(链接库名称 SHARED 链接库代码) add_library(dll_ SHARED dll_.cpp) dll_.cpp #include <iostream> using namespace std; // c++ 结构体定义 struct cpp_struck_ { // 股票代码,字符串 char *stock_name_; // 日期,字符串

结构体指针

结构体与指针 1.结构体指针的数值为某个结构体的内存空间的地址,从而指针指向某个结构体. 2.结构体指针的初始值为空(0),不指向任何结构体. 3.malloc操作:创建一个新的内存空间(从内存中选择一个内存空间存储结构体),p指向这个结构体,p的值为这个结构体的内存空间的地址. 4.结构体指针的赋值:一个结构体指针的数值等于另外一个结构体指针的数值,从而两个结构体指针指向相同的结构体.当对某个结构体进行访问时,选择的结构体指针只要满足该结构体指针指向这个结构体即可,即可以有很多种选择. 5.当

结构体指针概要

结构体指针 指针当做函数参数 数组当做函数参数 1.结构体指针 指向结构体变量的指针.称为结构体指针 Student stu ={0}; Student *p = &stu; Student  * 结构体指针类型(类型), p结构体指针变量(变量名); &stu 结构体变量地址(初值) (*p).sex = 'm'; p->sex= 'm'; (*p)对指针取值后是结构体变量,.sex是访问成员变量 使用指针可以指向操作符直接访问结构体成员p->sex 1.结构体指针 结构体指

cdev成员结构体file_operations文件操作结构的分析

struct file_operations{ struct module *owner; // 指向拥有该结构的模块的指针,避免正在操作时被卸载,一般为初始化为THIS_MODULES loff_t (*llseek) (struct file *, loff_t, int); // llseek用来修改文件当前的读写位置,返回新位置 // loff_t为一个”长偏移量”.当此函数指针为空,seek调用将会以不可预期的方式修改file结构中的位置计数器. ssize_t (*read) (st

结构体指针和结构体成员指针

在添加sqlite3的加解密功能函数时,由于网上资料针对的版本是旧版sqlite3源码,现在新版上做修改遇到了一个宏,该宏是旧版上的,它作用是由结构体成员指针pData找到它所属的结构体指针.下面转的文章详解了这种机制. 1.通过结构体成员指针寻找其所属结构体指针 转自http://blog.csdn.net/mycwq/article/details/9327743 宏CONTAINING_RECORD,可以直接根据结构体成员指针找到结构体指针. 我们看一下它的定义: 1 #define CO

(C)struct结构体指针

结构体指针 指针结构与指针的关系亦有两重:其一是在定义结构时,将指针作为结构中的一个成员:其二是指向结构的指针(称为结构指针). 前者同一般的结构成员一样可直接进行访问,后者是本节讨论的重点. 结构指针说明的一般形式是: struct (结构类型名称) * (结构指针变量名);例如:struct date * pdate, today;说明了两个变量,一个是指向结构date的结构指针pdate,today是一个date结构变量. 语句: struct date{ int year; int mo

几年前做家教写的C教程(之五专讲结构体与文件操作)

C语言学习宝典(5) 结构体: 将不同类型的数据组合成为一个有机的整体,这个整体就是一个结构体. 例如: Struct student { Int name; Char sex; Float score; }: 使用方法: 类型名 成员名: 一般形式: Struct { 成员列表: }变量名表列: 结构体变量的引用: 结构体变量名.成员名 文件: FILE  *fp; Fp=fopen(文件名,文件打开方式): Fclose(文件指针) 例1  对候选人得票的统计程序,设有3个后选人,每次输入一

C9_结构体指针

.h // //  MyFunction.h //  C9_结构体指针 // //  Created by dllo on 15/7/10. //  Copyright (c) 2015年 zhozhicheng. All rights reserved. // #import <Foundation/Foundation.h> // 结构体 // 学生:姓名,年龄,性别,成绩 struct student{ char stuName[20]; int  stuAge; char stuSex

C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 本文由 arthinking 发表于315 天前 ⁄ itzhai.com原创文章 ⁄ C语言 ⁄ 评论数 3 ⁄ 被围观 1,775 views+ 指针数组: 在一个数组中,如果它的元素全部都是指针类