题目来自于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.

 /*
This program was written by Richard Chad Sparrow
as a test case for AB-testing the hazard management
system.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct hazard {
char *description;
void *extraData;
int extraDataType;
int id;
char severityClass;
};
void printHazard(struct hazard *hazard);
int main(int argc, char **argv){
struct hazard hazard1;
struct hazard hazard2;
struct hazard *lastHazard;
/* Hazard data setup. */
hazard1.description = "Brake service required.";
hazard1.extraData = NULL;
hazard1.extraDataType = ;
hazard1.id = ;
hazard1.severityClass = 'A';
hazard2.description = "Unknown issue in fluid level.";
hazard2.extraData = NULL;
hazard2.extraDataType = ;
hazard2.id = ;
hazard2.severityClass = 'U';
lastHazard = &hazard2;
printf("Hazards after setup:\n");
printHazard(&hazard1);
printHazard(&hazard2);
/*
The brake service hazard has been present for multiple
services, so needs to be updated to severity class 'B'.
*/
/* Original: hazard1.severityClass = 'B'; */
/* CHANGE THE CODE HERE: */
hazard1.severityClass = 'B';
printf("Hazard 1 after class B severity update:\n");
printHazard(&hazard1);
/*
The next hazard to be evaluted has been evaluated and
its severity class has been found to be quite serious,
class 'D'. As part of this issue, the id has also been
increased to 3 and the hazard description has been
changed to "Fluid leak in tank 4".
*/
/* Original: lastHazard->severityClass = 'D'; */
/* CHANGE THE CODE HERE: */
lastHazard->severityClass = 'D'; /* Original: lastHazard->description = "Fluid leak in tank 4"; */
/* CHANGE THE CODE HERE: */
lastHazard->description = "Fluid leak in tank 4";
printf("Hazard 2 after description and D-class update:\n");
printHazard(&hazard2);
return ;
}
void printHazard(struct hazard *hazard){
printf("Hazard %d: %s [Class %c, extraDataType: %d]\n",
hazard->id, hazard->description, hazard->severityClass,
hazard->extraDataType);
}

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

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

第一条:

 hazard1.severityClass = 'B';

替换为:

     //*(char *)((void *)(&hazard1) + offsetof(struct hazard, severityClass)) = 'B';
*(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根据成员在结构体中定义的顺序进行偏移。

最后一条:

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

替换为:

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

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

答案:

 /*
This program was written by Richard Chad Sparrow
as a test case for AB-testing the hazard management
system.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct hazard {
char *description;
void *extraData;
int extraDataType;
int id;
char severityClass;
};
void printHazard(struct hazard *hazard);
int main(int argc, char **argv){
struct hazard hazard1;
struct hazard hazard2;
struct hazard *lastHazard;
/* Hazard data setup. */
hazard1.description = "Brake service required.";
hazard1.extraData = NULL;
hazard1.extraDataType = ;
hazard1.id = ;
hazard1.severityClass = 'A';
hazard2.description = "Unknown issue in fluid level.";
hazard2.extraData = NULL;
hazard2.extraDataType = ;
hazard2.id = ;
hazard2.severityClass = 'U';
lastHazard = &hazard2;
printf("Hazards after setup:\n");
printHazard(&hazard1);
printHazard(&hazard2);
/*
The brake service hazard has been present for multiple
services, so needs to be updated to severity class 'B'.
*/
/* Original: hazard1.severityClass = 'B'; */
/* CHANGE THE CODE HERE:
//hazard1.severityClass = 'B';*/ //*(char *)((void *)(&hazard1) + offsetof(struct hazard, severityClass)) = 'B';
*(char *)((void *)(&hazard1) + sizeof(char *) + sizeof(void *) + sizeof(int) + sizeof(int)) = 'B'; printf("Hazard 1 after class B severity update:\n");
printHazard(&hazard1);
/*
The next hazard to be evaluted has been evaluated and
its severity class has been found to be quite serious,
class 'D'. As part of this issue, the id has also been
increased to 3 and the hazard description has been
changed to "Fluid leak in tank 4".
*/
/* Original: lastHazard->severityClass = 'D'; */
/* CHANGE THE CODE HERE:
lastHazard->severityClass = 'D';*/ *(char *)((void *)(lastHazard) + offsetof(struct hazard, severityClass)) = 'D'; /* Original: lastHazard->description = "Fluid leak in tank 4"; */
/* CHANGE THE CODE HERE:
lastHazard->description = "Fluid leak in tank 4";*/ //*(char **)((void *)(lastHazard) + offsetof(struct hazard, description)) = "Fluid leak in tank 4";
//*(char **)((void *)(lastHazard)) = "Fluid leak in tank 4";
*(char **)(lastHazard) = "Fluid leak in tank 4"; printf("Hazard 2 after description and D-class update:\n");
printHazard(&hazard2);
return ;
}
void printHazard(struct hazard *hazard){
printf("Hazard %d: %s [Class %c, extraDataType: %d]\n",
hazard->id, hazard->description, hazard->severityClass,
hazard->extraDataType);
}

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

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

    CMakeLists.txt # project(工程名) project(blog-3123958139-1) # add_library(链接库名称 SHARED 链接库代码) add_libra ...

  2. 嵌入式-C语言:通过结构体指针操作结构体内容

    #include<stdio.h> #include<string.h> struct Student { char name[32]; int age; int height ...

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

    struct file_operations{ struct module *owner; // 指向拥有该结构的模块的指针,避免正在操作时被卸载,一般为初始化为THIS_MODULES loff_t ...

  4. 【C语言入门教程】7.3 结构体指针的定义和引用

    C 语言中指针的操作非常灵活,它也能指向结构体变量对结构体变量进行操作.在学习结构指针之前,需要再次加深对指针的认识.声明指针变量时所使用的数据类型修饰符实际上的作用是定义指针访问内存的范围,如果指针 ...

  5. c语言结构体指针初始化

    今天来讨论一下C中的内存管理. 记得上周在饭桌上和同事讨论C语言的崛起时,讲到了内存管理方面 我说所有指针使用前都必须初始化,结构体中的成员指针也是一样 有人反驳说,不是吧,以前做二叉树算法时,他的左 ...

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

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

  7. c语言结构体指针必须初始化

    先说结论 结构体指针需要初始化 结构体指针的成员指针同样需要初始化 结构体变量定义的时候就已经分配了内存空间,而上面两个确没有 struct test{ int i; struct buf *p;} ...

  8. C语言结构体指针初始化(转)

    reference: https://www.cnblogs.com/losesea/archive/2012/11/15/2772526.html 今天来讨论一下C中的内存管理. 记得上周在饭桌上和 ...

  9. (C)struct结构体指针

    结构体指针 指针结构与指针的关系亦有两重:其一是在定义结构时,将指针作为结构中的一个成员:其二是指向结构的指针(称为结构指针). 前者同一般的结构成员一样可直接进行访问,后者是本节讨论的重点. 结构指 ...

随机推荐

  1. DSAPI多功能组件编程应用-使用外部字体(包括资源文件)

    在软件开发过程中,尤其是比较个性化的程序,有时会需要使用非安装字体文件,比如发布的时候附带了一个专用字体,或者该字体文件直接被放入项目资源,当不希望把这个字体安装到用户的操作系统但又想使用它时,本示例 ...

  2. VBA中使用正则的两种方式

    第一种方式(需要引用VBScript RegularExpression 5.5类库) Option Explicit Sub RegularExpresstion()'方法块 Dim regex A ...

  3. Oracle day03 连表查询

    为什么要表连接进行查询? 查询部门名称为SALES的员工信息 如何进行表的连接查询? 两种方式:Sql 1992 和sql1999 sql1992sql分类    1.笛卡尔积 (表乘表)    2. ...

  4. vue 如何点击按钮返回上一页

    1,vue 如何点击按钮返回上一页呢? 这是vue挂载的范围html代码 <div @click="goOff()">返回</div> 下面是点击返回的方法 ...

  5. 程序员奇谈之我写的程序不可能有bug篇

    程序员在普通人的印象里是一份严(ku)谨(bi)的职业,也是一个被搞怪吐槽乐此不疲的职业,程序员们面对复杂的代码敲打电脑时连眉头都不会皱一下,但是有一个词却是他们痛苦的根源,它就是Bug. 有不少的新 ...

  6. Vue项目用了脚手架vue-cli3.0,会报错You are using the runtime-only build of Vue where the template compiler is not available.....

    摘自: https://blog.csdn.net/wxl1555/article/details/83187647 报错信息如下图: 报错原因是:vue有两种形式的代码:一种是compiler(模版 ...

  7. 广州.NET微软技术俱乐部休闲活动 - 每周三五晚周日下午爬白云山活动

    基于如下原因: 正如我们在<广州.NET微软技术俱乐部与其他技术群的区别>里面提到的:有人在活动中表达"少了一点自由交流的时间, 我们来自五湖四海, 希望多点时间彼此认识&quo ...

  8. Python进阶之模块

    在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很 ...

  9. C# 动态生成word文档

    本文以一个简单的小例子,简述利用C#语言开发word表格相关的知识,仅供学习分享使用,如有不足之处,还请指正. 在工程中引用word的动态库 在项目中,点击项目名称右键-->管理NuGet程序包 ...

  10. (简单)华为荣耀9i LLD-AL20的Usb调试模式在哪里开启的方法

    每当我们使用pc通过数据线连接上安卓手机的时候,如果手机没有开启Usb开发者调试模式,pc则没法成功检测到我们的手机,有时,我们使用的一些功能较好的应用如以前我们使用的一个应用引号精灵,老版本就需要开 ...