题目来自于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. XML——对XML文档的创建与增删改查

    一.创建的第一种方式  //1.创建一个XML文档 XmlDocument doc = new XmlDocument(); //2.创建第一行描述信息 XmlDeclaration dec = do ...

  2. ElasticSearch6学习(1)-安装Elasticsearch

    安装准备: 安装Elasticsearch唯一的要求是安装Java8,包括对应的Jdk.其他java9/java10没尝试,考虑兼容问题.我这里只用了java8 安装java8可以参考我之前写的一篇文 ...

  3. ajaxFileUpload onchang上传文件插件第二次失效刷新一次才能再次调用触发change事件

    关于用ajaxfileupload时,遇到一个要刷新一次页面才能再次上传, ajaxFileUpload 用onchang上传只能上传一次 第二次就失效了 我找这个问题找了很长时间 ajaxFileU ...

  4. vue中computed计算属性与methods对象中的this指针

    this 指针问题 methods与computed中的this指针 应该指向的是它们自己,可是为什么this指针却可以访问data对象中的成员呢? 因为new Vue对象实例化后data中的成员和c ...

  5. Vue开篇之Vue-cli搭建项目

    介绍 Vue.js是一套构建用户界面的渐进式框架.Vue 只关注视图层,采用自底向上增量开发的设计.Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. 第一步:安装node ...

  6. eclipse配置freemarker,*.ftl文件

    亲测,提供2种方式,效果都不错: ----------------------------------------- 1.直接下载相应的插件.只需要下载FreeMarker的识别Jar包就可以:888 ...

  7. Python 使用Python远程连接并操作InfluxDB数据库

    使用Python远程连接并操作InfluxDB数据库 by:授客 QQ:1033553122 实践环境 Python 3.4.0 CentOS 6 64位(内核版本2.6.32-642.el6.x86 ...

  8. linux下的qt串口通信

    1.linux下的qt串口通信跟windows唯一的差别就是端口号的名字,windows下面是COM,而linux是ttyUSB0的路径 2.一般情况下linux插上USB转串口线就可以在/dev/目 ...

  9. Vue2.5笔记:Vue的实例与生命周期

    理解与认识 Vue 的实例是我们学习 Vue 非常重要的一步,也是非常必须的,因为实例是它的一个起点,也是它的一个入口,只有我们创建一个 Vue 实例之后,我们才行利用它进行一些列的操作. 首先 Vu ...

  10. C# Debug和release判断用法

    C# Debug和release判断用法 #if (!DEBUG) Response.Write("DEBUG下运行");#else Response.Write("re ...