使用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.
/*
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对结构体指针偏移操作的更多相关文章
- ctypes 操作 python 与 c++ dll 互传结构体指针
CMakeLists.txt # project(工程名) project(blog-3123958139-1) # add_library(链接库名称 SHARED 链接库代码) add_libra ...
- 嵌入式-C语言:通过结构体指针操作结构体内容
#include<stdio.h> #include<string.h> struct Student { char name[32]; int age; int height ...
- cdev成员结构体file_operations文件操作结构的分析
struct file_operations{ struct module *owner; // 指向拥有该结构的模块的指针,避免正在操作时被卸载,一般为初始化为THIS_MODULES loff_t ...
- 【C语言入门教程】7.3 结构体指针的定义和引用
C 语言中指针的操作非常灵活,它也能指向结构体变量对结构体变量进行操作.在学习结构指针之前,需要再次加深对指针的认识.声明指针变量时所使用的数据类型修饰符实际上的作用是定义指针访问内存的范围,如果指针 ...
- c语言结构体指针初始化
今天来讨论一下C中的内存管理. 记得上周在饭桌上和同事讨论C语言的崛起时,讲到了内存管理方面 我说所有指针使用前都必须初始化,结构体中的成员指针也是一样 有人反驳说,不是吧,以前做二叉树算法时,他的左 ...
- C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com
原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...
- c语言结构体指针必须初始化
先说结论 结构体指针需要初始化 结构体指针的成员指针同样需要初始化 结构体变量定义的时候就已经分配了内存空间,而上面两个确没有 struct test{ int i; struct buf *p;} ...
- C语言结构体指针初始化(转)
reference: https://www.cnblogs.com/losesea/archive/2012/11/15/2772526.html 今天来讨论一下C中的内存管理. 记得上周在饭桌上和 ...
- (C)struct结构体指针
结构体指针 指针结构与指针的关系亦有两重:其一是在定义结构时,将指针作为结构中的一个成员:其二是指向结构的指针(称为结构指针). 前者同一般的结构成员一样可直接进行访问,后者是本节讨论的重点. 结构指 ...
随机推荐
- javascript基础修炼(2)——What's this(上)
目录 一.this是什么 二.近距离看this 三. this的一般指向规则 四. 基本规则示例 五. 后记 开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一.thi ...
- 第50章 设备授权端点(Device Authorization Endpoint) - Identity Server 4 中文文档(v1.0.0)
设备授权端点可用于请求设备和用户代码.此端点用于启动设备流授权过程. 注意 终端会话端点的URL可通过发现端点获得. client_id 客户标识符(必填) client_secret 客户端密钥可以 ...
- Odd-e CSD Course Day 2
首先在第二天中其實談的更多的是在於 Test-Driven 的部分,而第一天談的偏向如何寫出一個好的 A-TDD 案例 但在第二天開始,就不太會照固定的 Topic 進行講述,而且讓團隊成員就像一個真 ...
- MySQL 笔记整理(6) --全局锁和表锁:给表加个字段怎么有这么多阻碍
笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> 6) --全局锁和表锁:给表加个字段怎么有这么多阻碍 数据库锁设计的初衷是处理并发问题.作为多用户共享的资源,当出现并发访问的时候, ...
- 杭电ACM2008--数值统计
数值统计 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- 你必须知道的.net读书笔记第四回:后来居上:class和struct
基本概念 1.1. 什么是class? class(类)是面向对象编程的基本概念,是一种自定义数据结构类型,通常包含字段.属性.方法.属性.构造函数.索引器.操作符等.因为是基本的概念,所以不必在此 ...
- Spring Boot使用AOP在控制台打印请求、响应信息
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等. AOP简介 AOP全称Aspect Oriented Programming,面向切面,AOP主要实现的 ...
- string[]转list<long>,List转字符串
List转字符串,用逗号隔开 List<string> list = new List<string>();list.Add("a");list.Add(& ...
- MySQL5.7开多实例指导
一.mysql多实例原理 在一台服务器上,mysql服务开启多个不同的端口,运行多个服务进程.他们通过不同的 socket来监听不同的端口互不干扰地运行. 二.开发环境 ubuntu16.04.5LT ...
- 微信小程序picker的坑
js文件: Companyarr: [{ id: '公司id1', companyname: "公司1的名字" }, { id: '公司id2', companyname: &qu ...