zoukankan      html  css  js  c++  java
  • 使用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:
    ");
    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:
    ");
    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:
    ");
    60     printHazard(&hazard2);
    61     return 0;
    62 }
    63 void printHazard(struct hazard *hazard){
    64     printf("Hazard %d: %s [Class %c, extraDataType: %d]
    ",
    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:
    ");
    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:
    ");
    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:
    ");
    71     printHazard(&hazard2);
    72     return 0;
    73 }
    74 void printHazard(struct hazard *hazard){
    75     printf("Hazard %d: %s [Class %c, extraDataType: %d]
    ",
    76     hazard->id, hazard->description, hazard->severityClass,
    77     hazard->extraDataType);
    78 }
  • 相关阅读:
    socket bind详解
    Hibernate简单的基础理论
    Web的工作机制
    部署hibernate框架项目时出现问题:The type java.lang.Object cannot be resolved. It is indirectly referenced from required .class files.
    Spring简单的小例子SpringDemo,用于初略理解什么是Spring以及JavaBean的一些概念
    Hibernate项目里配置环境时,jar包配置不当会对测试结果产生影响。
    转载——Struts2中的constant详解
    同样的WiFi,手机能连上网,电脑不能。错误代码DNS_PROBE_POSSIBLE
    eclipse外部导入Javaweb项目时,项目上出现红叉的一个可能的解决办法
    依赖注入的实现方式:设值注入和构造方法注入
  • 原文地址:https://www.cnblogs.com/Will-zyq/p/10049052.html
Copyright © 2011-2022 走看看