代码之家  ›  专栏  ›  技术社区  ›  Christoffer

将结构指针的大小增加一半

  •  2
  • Christoffer  · 技术社区  · 17 年前

    我只是有一个有趣的问题要处理,我看不出有什么好办法来解决它。

    typedef struct _node_t node_t;
    typedef struct _graph_t graph_t;
    
    struct {
        /* Data fields omitted */
        node_t * pNextByLevel;
        node_t * pNextByProximity;
        node_t * pNextByRank;
    } node_t;
    
    struct {
        /* Data fields omitted */
        size_t nNodes;
        size_t nMaxNodes;
        node_t * pFirstByLevel;
        node_t * pFirstByProximity;
        node_t * pFirstByRank;
    } graph_t;
    

    实际节点的布局紧跟在标题之后,因此通常使用

    graph_t * pNewBuffer = calloc(1, sizeof(graph_t) + nMaxNodes * sizeof(node_t));
    pNewBuffer->nMaxNodes = nMaxNodes;
    

    node_t * pNewBufferNodes = (node_t *) &pNewBuffer[1];
    

    现在,有一个支持函数在缓冲区上运行,可以减少节点的数量。它看起来像这样:

    status_t reduce(graph_t** ppBuffer)
    {
        graph_t * pReplacement, * pOld = *ppBuffer;
        size_t nRequired; 
        node_t * oldBuffer = (node_t *) &pOld[1];
    
        /* complex calculation ultimately computes 'nRequired' */
    
        pReplacement = realloc(pOld, sizeof(graph_t) + nRequired * sizeof(node_t));
    
        if ( pReplacement != pOld )
        {
            int i;
            node_t * newBuffer = (node_t *) &pReplacement[1];
            ptrdiff_t offset = newBuffer - oldBuffer;
    
            for ( i = 0; i < requiredNodes; i++ )
            {
                newBuffer[i].pFirstByLevel += offset;
                newBuffer[i].pFirstBySimilarity += offset;
                newBuffer[i].pFirstByRank += offset;
            }
            *ppBuffer = pReplacement;
        }
    }
    

    现在让我困惑的是,当使用新模块的缩减功能时,输入没有“正确”对齐。当我检查地址时,我注意到以下属性:

     ((char *) newBuffer - (char *) oldBuffer) % sizeof(graph_t) == 0
     ((size_t) newBuffer) % sizeof(node_t) == 0
     ((size_t) oldBuffer) % sizeof(node_t) == 0
     ((char *) newBuffer - (char *) oldBuffer) % sizeof(node_t) == sizeof(node_t) / 2
    

    这可以归结为我的问题——当偏移量不能表示为元素的整数时,您是否看到一种增加指针的简洁方法?

    找到不需要过度施法的方法的额外积分:)

    3 回复  |  直到 17 年前
        1
  •  2
  •   neuro    17 年前

    关于ptrdiff_t:“这是两个指针之间的减法运算返回的类型。这是一个有符号的整数类型,因此可以强制转换为兼容的基本数据类型。两个指针的减法运算仅被授予对指向相同数组元素的指针具有有效定义值的权限(或对于刚好超过数组中最后一个的元素)。对于其他值,行为取决于系统特征和编译器实现。”

    无奖励积分解决方案是将指针转换为char*以计算偏移量。最终将得到以字节为单位的偏移量。然后可以使用强制转换添加字节偏移量。为了最小化转换,您可以编写一个helper函数,为节点指针设置正确的值。

    如果您想使用realloc,我看不到其他解决方案,因为您的初始数组是由realloc释放的。字节偏移量似乎是唯一的方法。

    我希望有帮助。告诉我我是否误解了。。。

        2
  •  1
  •   Dingo    17 年前

    newBuffer[i].pFirstByLevel = newBuffer[i].pFirstByLevel - oldBuffer + newBuffer;            
    newBuffer[i].pFirstBySimilarity = newBuffer[i].pFirstBySimilarity - oldBuffer + newBuffer;            
    newBuffer[i].pFirstByRank = newBuffer[i].pFirstByRank - oldBuffer + newBuffer;
    
        3
  •  1
  •   ephemient    17 年前

    你的语法搞砸了。结构标签名称位于结构定义之前;之后的任何事情都是声明。

    任何一个

    typedef struct _node_t {
        /* Data fields omitted */
        node_t * pNextByLevel;
        node_t * pNextByProximity;
        node_t * pNextByRank;
    } node_t;
    

    typedef struct _graph_t graph_t;
    struct _graph_t {
        /* Data fields omitted */
        size_t nNodes;
        size_t nMaxNodes;
        node_t * pFirstByLevel;
        node_t * pFirstByProximity;
        node_t * pFirstByRank;
    };
    

    就是你想写的。


    /* same node_t as before */
    typedef struct _node_t {...} node_t;
    /* same graph_t as before */
    typedef struct _graph_header_t {...} graph_header_t;
    /* new type */
    typedef struct _graph_t {
        graph_header_t header;
        node_t nodes[1];
    } graph_t;
    
    graph_t pNewBuffer = calloc(1, sizeof(graph_t) + (nMaxNodes-1) * sizeof(node_t));
    

    它允许访问 pNewBuffer->nodes[i] 0 <= i < nMaxNodes

    现在,如果你能申报,这会更好 node_t nodes[0]

    C99推出“灵活的阵列成员”

    typedef struct _graph_t {
        graph_header_t header;
        node_t nodes[];
    } graph_t;
    

    sizeof(pNewBuffer->nodes) sizeof(graph_t) 等于如果有 node_t[] 数组有零个元素。