Use struct Alignment and Padding in C

本文详细讲解了如何在C语言中利用struct的对齐规则和填充来提高内存效率,通过实例展示了如何通过成员重组节省空间和理解__attribute__((packed))的作用。了解结构体对齐的基本原理,并学习如何利用这些技巧优化程序性能。

reference: Use struct Alignment and Padding in C | Delft Stack

This article will explain several methods of how to use struct alignment and padding in C.

Understand the Basics of Alignment and Padding in C

All objects in memory are represented as the primary data types like: charshortintlongpointer etc. These data types have their corresponding size in memory. On most contemporary 64-bit desktop processors, the sizes are 1 byte for a char, 2 bytes for a short, 4 bytes for an int, 8 bytes for a pointer, and so on. Note that these are not guaranteed sizes (except for char), but one can retrieve the object’s size using the sizeof operator. Now, alignment is the method that compilers employ to place variables in the memory, implying that each basic data type is stored at the address divisible by the corresponding size.

Usually, alignment is utilized to access data objects faster and efficiently. Alignment forces continuously declared different data types to include some spacing between their addresses. Namely, if we declare a structure st1 with one pointer and a char as shown in the following example, it will take up 16 bytes in total. Mind though, a single pointer takes 8 bytes and a char takes one byte, so one would think the st1struct must occupy 9 bytes. But it behaves as if all members are aligned to the largest member’s size (i.e. 8 bytes). st2 struct demonstrates a similar structure that occupies the same amount of memory, except that it has an array of 7 char members.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {

    typedef struct {
        char *p;
        char c2;
    } st1;

    typedef struct {
        char *p;
        char c2;
        char padding[7];
    } st2;

    printf("sizeof st1 = %zu\n", sizeof(st1));
    printf("sizeof st2 = %zu\n", sizeof(st2));

    exit(EXIT_SUCCESS);
}

Output:

sizeof st1 = 16
sizeof st2 = 16

Use Member Reordering Technique to Save Space in Objects in C

The previous example demonstrates that there’s some waste of memory when structures include different types and don’t fill up the alignment boundaries. Although, there are some cases where it might be possible to reorder structure members and save extra space.

The next example code defines foo1 struct that has the largest member (char *) in the middle and foo2 with the same member as the first one. The sizes of these two objects are different - 24 bytes and 16 bytes. This has to do with the ordering of the data members. In the foo1 structure, p needs to be aligned at the address that is divisible by 8, so the int and short before it will occupy 8 bytes in total and two chars after it will occupy the 8 bytes as well. Although, if we move p to the first place, the following members will squeeze into the 8 bytes and the alignment rule is satisfied as well. Thus, foo2’s size totals 16 bytes and it’s called to be packed struct. Note that the gcc compiler has the special __attribute__ ((packed)) specifier that can force even unordered struct members to be packed.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[]) {

    typedef struct {
        int n1;
        short s1;
        char *p;
        char c1;
        char c2;
    } foo1;

    typedef struct {
        char *p;
        int n1;
        short s1;
        char c1;
        char c2;
    } foo2;

    typedef struct {
        int n1;
        short s1;
        char *p;
        char c1;
        char c2;
    } __attribute__((packed)) foo3;

    printf("sizeof foo1 = %zu\n", sizeof(foo1));
    printf("sizeof foo2 = %zu\n", sizeof(foo2));
    printf("sizeof foo3 = %zu\n", sizeof(foo3));

    exit(EXIT_SUCCESS);
}

Output:

sizeof foo1 = 24
sizeof foo2 = 16
sizeof foo3 = 16

Write for us

DelftStack articles are written by software geeks like you. If you also would like to contribute to DelftStack by writing paid articles, you can check the write for us page.

Related Article - C Struct

/* * Vhost-user RDMA device : init and packets forwarding * * Copyright (C) 2025 KylinSoft Inc. and/or its affiliates. All rights reserved. * * Author: Xiong Weimin <xiongweimin@kylinos.cn> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #ifndef __VHOST_RDMA_IB_H__ #define __VHOST_RDMA_IB_H__ #include <netinet/in.h> #include <linux/virtio_net.h> #include <rte_spinlock.h> #include <rte_atomic.h> #include <rte_timer.h> #include "vhost_rdma.h" #include "eal_interrupts.h" #define OPCODE_NONE (-1) #define VIRTIO_IB_DEVICE_RC_RNR_NAK_GEN (1 << 0) #define VHOST_USER_MEMORY_MAX_NREGIONS 8 #define VHOST_USER_MAX_CONFIG_SIZE 256 #define VHOST_RDMA_CTRL_ROCE 6 #define VHOST_RDMA_CTRL_ROCE_QUERY_DEVICE 0 #define VHOST_RDMA_CTRL_ROCE_QUERY_PORT 1 #define VHOST_RDMA_CTRL_ROCE_CREATE_CQ 2 #define VHOST_RDMA_CTRL_ROCE_DESTROY_CQ 3 #define VHOST_RDMA_CTRL_ROCE_CREATE_PD 4 #define VHOST_RDMA_CTRL_ROCE_DESTROY_PD 5 #define VHOST_RDMA_CTRL_ROCE_GET_DMA_MR 6 #define VHOST_RDMA_CTRL_ROCE_ALLOC_MR 7 #define VHOST_RDMA_CTRL_ROCE_REG_USER_MR 9 #define VHOST_RDMA_CTRL_ROCE_MAP_MR_SG 8 #define VHOST_RDMA_CTRL_ROCE_DEREG_MR 10 #define VHOST_RDMA_CTRL_ROCE_CREATE_QP 11 #define VHOST_RDMA_CTRL_ROCE_MODIFY_QP 12 #define VHOST_RDMA_CTRL_ROCE_QUERY_QP 13 #define VHOST_RDMA_CTRL_ROCE_DESTROY_QP 14 #define VHOST_RDMA_CTRL_ROCE_QUERY_PKEY 15 // #define VHOST_RDMA_CTRL_ROCE_CREATE_AH 13 // #define VHOST_RDMA_CTRL_ROCE_DESTROY_AH 14 #define VHOST_RDMA_CTRL_ROCE_ADD_GID 16 #define VHOST_RDMA_CTRL_ROCE_DEL_GID 17 #define VHOST_RDMA_CTRL_ROCE_REQ_NOTIFY_CQ 18 enum vhost_rdma_ib_qp_state { VHOST_RDMA_IB_QPS_RESET, VHOST_RDMA_IB_QPS_INIT, VHOST_RDMA_IB_QPS_RTR, VHOST_RDMA_IB_QPS_RTS, VHOST_RDMA_IB_QPS_SQD, VHOST_RDMA_IB_QPS_SQE, VHOST_RDMA_IB_QPS_ERR }; enum vhost_rdma_ib_mtu { VHOST_RDMA_IB_MTU_256 = 1, VHOST_RDMA_IB_MTU_512 = 2, VHOST_RDMA_IB_MTU_1024 = 3, VHOST_RDMA_IB_MTU_2048 = 4, VHOST_RDMA_IB_MTU_4096 = 5 }; enum vhost_rdma_ib_wc_status { /* Operation completed successfully */ VHOST_RDMA_IB_WC_SUCCESS, /* Local Length Error */ VHOST_RDMA_IB_WC_LOC_LEN_ERR, /* Local QP Operation Error */ VHOST_RDMA_IB_WC_LOC_QP_OP_ERR, /* Local Protection Error */ VHOST_RDMA_IB_WC_LOC_PROT_ERR, /* Work Request Flushed Error */ VHOST_RDMA_IB_WC_WR_FLUSH_ERR, /* Bad Response Error */ VHOST_RDMA_IB_WC_BAD_RESP_ERR, /* Local Access Error */ VHOST_RDMA_IB_WC_LOC_ACCESS_ERR, /* Remote Invalid Request Error */ VHOST_RDMA_IB_WC_REM_INV_REQ_ERR, /* Remote Access Error */ VHOST_RDMA_IB_WC_REM_ACCESS_ERR, /* Remote Operation Error */ VHOST_RDMA_IB_WC_REM_OP_ERR, /* Transport Retry Counter Exceeded */ VHOST_RDMA_IB_WC_RETRY_EXC_ERR, /* RNR Retry Counter Exceeded */ VHOST_RDMA_IB_WC_RNR_RETRY_EXC_ERR, /* Remote Aborted Error */ VHOST_RDMA_IB_WC_REM_ABORT_ERR, /* Fatal Error */ VHOST_RDMA_IB_WC_FATAL_ERR, /* Response Timeout Error */ VHOST_RDMA_IB_WC_RESP_TIMEOUT_ERR, /* General Error */ VHOST_RDMA_IB_WC_GENERAL_ERR }; enum vhost_rdma_res_state { VHOST_RDMA_RES_STATE_NEXT, VHOST_RDMA_RES_STATE_NEW, VHOST_RDMA_RES_STATE_REPLAY, }; enum vhost_user_rdma_request { VHOST_USER_NONE = 0, VHOST_USER_GET_FEATURES = 1, VHOST_USER_SET_FEATURES = 2, VHOST_USER_SET_OWNER = 3, VHOST_USER_RESET_OWNER = 4, VHOST_USER_SET_MEM_TABLE = 5, VHOST_USER_SET_LOG_BASE = 6, VHOST_USER_SET_LOG_FD = 7, VHOST_USER_SET_VRING_NUM = 8, VHOST_USER_SET_VRING_ADDR = 9, VHOST_USER_SET_VRING_BASE = 10, VHOST_USER_GET_VRING_BASE = 11, VHOST_USER_SET_VRING_KICK = 12, VHOST_USER_SET_VRING_CALL = 13, VHOST_USER_SET_VRING_ERR = 14, VHOST_USER_GET_PROTOCOL_FEATURES = 15, VHOST_USER_SET_PROTOCOL_FEATURES = 16, VHOST_USER_GET_QUEUE_NUM = 17, VHOST_USER_SET_VRING_ENABLE = 18, VHOST_USER_GET_CONFIG = 24, VHOST_USER_SET_CONFIG = 25, VHOST_USER_MAX }; struct vhost_rdma_qp_cap { uint32_t max_send_wr; uint32_t max_send_sge; uint32_t max_recv_wr; uint32_t max_recv_sge; uint32_t max_inline_data; }; struct vhost_rdma_global_route { /* Destination GID or MGID */ uint8_t dgid[16]; /* Flow label */ uint32_t flow_label; /* Source GID index */ uint8_t sgid_index; /* Hop limit */ uint8_t hop_limit; /* Traffic class */ uint8_t traffic_class; }; struct vhost_rdma_ah_attr { /* Global Routing Header (GRH) attributes */ struct vhost_rdma_global_route grh; uint8_t sl; uint8_t static_rate; uint8_t port_num; uint8_t ah_flags; /* Destination MAC address */ uint8_t dmac[6]; }; struct vhost_rdma_qp_attr { enum vhost_rdma_ib_qp_state qp_state; enum vhost_rdma_ib_qp_state cur_qp_state; enum vhost_rdma_ib_mtu path_mtu; uint32_t qkey; uint32_t rq_psn; uint32_t sq_psn; uint32_t dest_qp_num; uint32_t qp_access_flags; uint8_t sq_draining; uint8_t max_rd_atomic; uint8_t max_dest_rd_atomic; uint8_t min_rnr_timer; uint8_t timeout; uint8_t retry_cnt; uint8_t rnr_retry; uint32_t rate_limit; struct vhost_rdma_qp_cap cap; struct vhost_rdma_ah_attr ah_attr; }; struct vhost_rdma_pd { struct vhost_rdma_device *dev; uint32_t pdn; rte_atomic32_t refcnt; }; struct vhost_rdma_queue { struct vhost_queue *vq; void *data; size_t elem_size; size_t num_elems; uint16_t consumer_index; uint16_t producer_index; struct rte_intr_handle intr_handle; rte_intr_callback_fn cb; }; /** Fixed-size vhost_memory struct */ struct vhost_memory_padded { uint32_t nregions; uint32_t padding; struct vhost_memory_region regions[VHOST_USER_MEMORY_MAX_NREGIONS]; }; /** Get/set config msg payload */ struct vhost_user_rdma_config { uint32_t offset; uint32_t size; uint32_t flags; uint8_t region[VHOST_USER_MAX_CONFIG_SIZE]; }; struct vhost_user_rdma_msg { enum vhost_user_rdma_request request; #define VHOST_USER_VERSION_MASK 0x3 #define VHOST_USER_REPLY_MASK (0x1 << 2) uint32_t flags; uint32_t size; /**< the following payload size */ union { #define VHOST_USER_VRING_IDX_MASK 0xff #define VHOST_USER_VRING_NOFD_MASK (0x1 << 8) uint64_t u64; struct vhost_vring_state state; struct vhost_vring_addr addr; struct vhost_memory_padded memory; struct vhost_user_rdma_config cfg; } payload; } __rte_packed; struct vhost_rdma_cq { struct vhost_queue *vq; rte_spinlock_t cq_lock; uint8_t notify; bool is_dying; uint32_t cqn; rte_atomic32_t refcnt; }; struct vhost_rdma_sq { rte_spinlock_t lock; /* guard queue */ struct vhost_rdma_queue queue; }; struct vhost_rdma_rq { rte_spinlock_t lock; /* guard queue */ struct vhost_rdma_queue queue; }; struct vhost_rdma_av { /* From RXE_NETWORK_TYPE_* */ uint8_t network_type; uint8_t dmac[6]; struct vhost_rdma_global_route grh; union { struct sockaddr_in _sockaddr_in; struct sockaddr_in6 _sockaddr_in6; } sgid_addr, dgid_addr; }; struct vhost_rdma_task { char name[8]; int state; bool destroyed; rte_atomic16_t sched; rte_spinlock_t state_lock; /* spinlock for task state */ struct rte_ring *task_ring; int (*func)(void *arg); void *arg; int ret; }; struct vhost_rdma_req_info { enum vhost_rdma_ib_qp_state state; int wqe_index; uint32_t psn; int opcode; rte_atomic32_t rd_atomic; int wait_fence; int need_rd_atomic; int wait_psn; int need_retry; int noack_pkts; struct vhost_rdma_task task; }; struct vhost_rdma_comp_info { uint32_t psn; int opcode; int timeout; int timeout_retry; int started_retry; uint32_t retry_cnt; uint32_t rnr_retry; struct vhost_rdma_task task; }; struct vhost_rdma_sge { __le64 addr; __le32 length; __le32 lkey; }; struct vhost_rdma_dma_info { uint32_t length; uint32_t resid; uint32_t cur_sge; uint32_t num_sge; uint32_t sge_offset; uint32_t reserved; union { uint8_t *inline_data; struct vhost_rdma_sge *sge; void *raw; }; }; struct vhost_rdma_recv_wqe { __aligned_u64 wr_id; __u32 num_sge; __u32 padding; struct vhost_rdma_dma_info dma; }; enum vhost_rdma_mr_type { VHOST_MR_TYPE_NONE, VHOST_MR_TYPE_DMA, VHOST_MR_TYPE_MR, }; enum vhost_rdma_mr_state { VHOST_MR_STATE_ZOMBIE, VHOST_MR_STATE_INVALID, VHOST_MR_STATE_FREE, VHOST_MR_STATE_VALID, }; struct vhost_rdma_mr { struct vhost_rdma_pd *pd; enum vhost_rdma_mr_type type; enum vhost_rdma_mr_state state; uint64_t va; uint64_t iova; size_t length; uint32_t offset; int access; uint32_t lkey; uint32_t rkey; uint32_t npages; uint32_t max_pages; uint64_t *pages; uint32_t mrn; rte_atomic32_t refcnt; }; struct vhost_rdma_resp_res { int type; int replay; uint32_t first_psn; uint32_t last_psn; uint32_t cur_psn; enum vhost_rdma_res_state state; union { struct { struct rte_mbuf *mbuf; } atomic; struct { struct vhost_rdma_mr *mr; uint64_t va_org; uint32_t rkey; uint32_t length; uint64_t va; uint32_t resid; } read; }; }; struct vhost_rdma_resp_info { enum vhost_rdma_ib_qp_state state; uint32_t msn; uint32_t psn; uint32_t ack_psn; int opcode; int drop_msg; int goto_error; int sent_psn_nak; enum vhost_rdma_ib_wc_status status; uint8_t aeth_syndrome; /* Receive only */ struct vhost_rdma_recv_wqe *wqe; /* RDMA read / atomic only */ uint64_t va; uint64_t offset; struct vhost_rdma_mr *mr; uint32_t resid; uint32_t rkey; uint32_t length; uint64_t atomic_orig; /* Responder resources. It's a circular list where the oldest * resource is dropped first. */ struct vhost_rdma_resp_res *resources; unsigned int res_head; unsigned int res_tail; struct vhost_rdma_resp_res *res; struct vhost_rdma_task task; }; struct vhost_rdma_qp { struct vhost_rdma_device *dev; struct vhost_rdma_qp_attr attr; uint32_t qpn; uint8_t type; unsigned int valid; unsigned int mtu; struct vhost_rdma_pd *pd; struct vhost_rdma_cq *scq; struct vhost_rdma_cq *rcq; uint8_t sq_sig_all; struct vhost_rdma_sq sq; struct vhost_rdma_rq rq; void *srq; // reversed uint32_t dst_cookie; uint16_t src_port; struct vhost_rdma_av av; struct rte_ring *req_pkts; struct rte_mbuf *req_pkts_head; // use this to support peek struct rte_ring *resp_pkts; struct vhost_rdma_req_info req; struct vhost_rdma_comp_info comp; struct vhost_rdma_resp_info resp; rte_atomic32_t ssn; rte_atomic32_t mbuf_out; int need_req_mbuf; /* Timer for retranmitting packet when ACKs have been lost. RC * only. The requester sets it when it is not already * started. The responder resets it whenever an ack is * received. */ struct rte_timer retrans_timer; uint64_t qp_timeout_ticks; /* Timer for handling RNR NAKS. */ struct rte_timer rnr_nak_timer; rte_spinlock_t state_lock; /* guard requester and completer */ rte_atomic32_t refcnt; }; struct vhost_user_rdma_sge { uint64_t addr; uint32_t length; uint32_t lkey; }; static inline int ib_mtu_enum_to_int(enum vhost_rdma_ib_mtu mtu) { switch (mtu) { case VHOST_RDMA_IB_MTU_256: return 256; case VHOST_RDMA_IB_MTU_512: return 512; case VHOST_RDMA_IB_MTU_1024: return 1024; case VHOST_RDMA_IB_MTU_2048: return 2048; case VHOST_RDMA_IB_MTU_4096: return 4096; default: return -1; } } void vhost_rdma_init_ib(struct vhost_rdma_device *dev); void vhost_rdma_destroy_ib(struct vhost_rdma_device *dev); void vhost_rdma_handle_ctrl_vq(void* arg); int vhost_rdma_task_scheduler(void *arg); void free_rd_atomic_resource(struct vhost_rdma_qp *qp, struct vhost_rdma_resp_res *res); void free_rd_atomic_resources(struct vhost_rdma_qp *qp); void vhost_rdma_mr_cleanup(void* arg); void vhost_rdma_qp_cleanup(void* arg); void vhost_rdma_queue_cleanup(struct vhost_rdma_qp *qp, struct vhost_rdma_queue* queue); #endif 也改一下
最新发布
10-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值