[算法題] 計算結構體的大小


計算結構體的大小

     C代碼中定義的結構體是一塊連續內存,各成員按照定義的順序依次在其中存放。編譯器在完成語法分析后,需要計算它的大小,然后才能正確地為結構體分配空間。為了讓結構體的所有成員都能正確、快速地訪問,需要字節對齊。

     字節對齊體現為:在成員之間可能增加補齊字節,以調整每個成員的偏移;結構體末尾,也可能增加補充字節。所有補齊字節計入結構體的大小。

     請寫一個程序來計算結構體的大小,要考慮字節對齊,同時要支持結構體多層嵌套的情況。

 

結構體大小的計算

成員在結構體內的偏移必須是它的字節對齊值的倍數。

 
l 字節對齊值: 
   1)基本類型char、short、int、double的字節對齊值依次為1、2、4、8。
   2)數組的字節對齊值等於它的一個元素的字節對齊值。
   3)結構體的字節對齊值等於它的所有成員的字節對齊值的最大值。
 
2 大小的計算: 
  1)基本類型char、short、int、double的大小依次為1、2、4、8字節。
  2)數組的大小等於它的一個元素的大小乘以元素個數。
  3)結構體的大小要補齊到它自己的字節對齊值的倍數,補齊字節在末尾。

 

要求

實現以下接口:

1.開始結構體定義 
2.添加基本類型成員
3.添加數組成員 
4.添加嵌套結構體成員
5.結束嵌套結構體成員
6.完成結構體定義,輸出它的大小 

 

調用者會保證: 

1.結構體的開始和結束是匹配的。 
2.不需要考慮空的結構體。
3.數組只限於一維的基本類型的數組。 
4.最多20層嵌套(嵌套的情況參考示例)
 
StructSize.h
#ifndef _STRUCT_SIZE_H
#define _STRUCT_SIZE_H

enum Type { CHAR_TYPE, SHORT_TYPE, INT_TYPE, DOUBLE_TYPE };

/*********************** 自定義數據結構 **************************/
typedef struct _tblNode
{
    enum Type type;
    int  size;
}tblNode;

typedef struct _structType
{
    int size;
    int align;
}StructType;
/******************************************************************/


/* 功能:開始定義結構體
 * 輸入:無
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int start_struct(void);

/* 功能:添加基本類型成員
 * 輸入:類型
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int add_basic_type(enum Type type);

/* 功能:添加數組類型成員
 * 輸入:type:數組元素類型
 *    number:數組元素數
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int add_array(enum Type type, unsigned int number);

/* 功能:添加嵌套結構體成員
 * 輸入:無
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int begin_nested_struct(void);

/* 功能:結束嵌套結構體成員
 * 輸入:無
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int end_nested_struct(void);

/* 功能:完成結構體定義,計算它的大小
 * 輸入:無
 * 輸出:size:結構體大小
 * 返回:正常返回0,失敗返回-1
 */
int finish_struct(unsigned int *size);

#endif
View Code

 

StructSize.cpp
// StructSize.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"
#include "StructSize.h"
#include <stdio.h>

#define PRINT_ON 0

tblNode g_tbl[] =
{
    {CHAR_TYPE,   1},
    {SHORT_TYPE,  2},
    {INT_TYPE,    4},
    {DOUBLE_TYPE, 8},
};

StructType g_astResult[20] = {0};
int g_iIndex = 0;

void Print(void)
{
#if PRINT_ON   
    printf("\nsize = %d \t align = %d", g_astResult[g_iIndex].size, g_astResult[g_iIndex].align);
#endif
}

/* 功能:開始定義結構體
 * 輸入:無
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int start_struct(void)
{
    g_iIndex = 0;
       g_astResult[g_iIndex].size  = 0;
    g_astResult[g_iIndex].align = 1;
    return 0;
}

/* 功能:添加基本類型成員
 * 輸入:類型
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int add_basic_type(enum Type type)
{
    int iSize = 0;
    
    if (type > DOUBLE_TYPE)
    {
        return -1;
    }

    iSize = g_tbl[type].size;
    while (0 != g_astResult[g_iIndex].size % iSize)
    {
        g_astResult[g_iIndex].size++;
    }

    g_astResult[g_iIndex].size += iSize;
    g_astResult[g_iIndex].align = (g_astResult[g_iIndex].align > iSize) ? g_astResult[g_iIndex].align : iSize;

    Print();
    return 0;
}

/* 功能:添加數組類型成員
 * 輸入:type:數組元素類型
 *    number:數組元素數
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int add_array(enum Type type, unsigned int number)
{
       int iSize = 0;
    
    if (type > DOUBLE_TYPE)
    {
        return -1;
    }

    iSize = g_tbl[type].size;
    while (0 != g_astResult[g_iIndex].size % iSize)
    {
        g_astResult[g_iIndex].size++;
    }

    g_astResult[g_iIndex].size += iSize * number;
    g_astResult[g_iIndex].align = (g_astResult[g_iIndex].align > iSize) ? g_astResult[g_iIndex].align : iSize;

    Print();
    return 0;
}

/* 功能:添加嵌套結構體成員
 * 輸入:無
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int begin_nested_struct(void)
{
    g_iIndex++;
    g_astResult[g_iIndex].size  = 0;
    g_astResult[g_iIndex].align = 1;

    Print();
    return 0;
}

/* 功能:結束嵌套結構體成員
 * 輸入:無
 * 輸出:無
 * 返回:正常返回0,失敗返回-1
 */
int end_nested_struct(void)
{
    int iFatherStructSize = 0;
    int iSonStructSize = 0;
    
       while (g_astResult[g_iIndex].size % g_astResult[g_iIndex].align != 0)
    {
        g_astResult[g_iIndex].size++;
    }
    g_iIndex--;

    if (g_iIndex >= 0)
    {
        iFatherStructSize = g_astResult[g_iIndex].align;
        iSonStructSize    = g_astResult[g_iIndex + 1].align;
        g_astResult[g_iIndex].align = (iFatherStructSize > iSonStructSize) ? iFatherStructSize : iSonStructSize;
        while(g_astResult[g_iIndex].size% g_astResult[g_iIndex].align != 0)
        {
            g_astResult[g_iIndex].size++;
        }
        g_astResult[g_iIndex].size += g_astResult[g_iIndex + 1].size;
    }

    Print();
    return 0;
}

/* 功能:完成結構體定義,計算它的大小
 * 輸入:無
 * 輸出:size:結構體大小
 * 返回:正常返回0,失敗返回-1
 */
int finish_struct(unsigned int *size)
{
    if (0 != g_iIndex)
    {
        return -1;
    }

    while (0 != g_astResult[g_iIndex].size % g_astResult[g_iIndex].align)
    {
        g_astResult[g_iIndex].size++;
    }
    *size = g_astResult[g_iIndex].size;
    
    Print();
    return 0;
}
View Code

 

main.cpp

// StructSize.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"
#include "StructSize.h"
#include <iostream>

void CPPUNIT_ASSERT(int iRet)
{
    if (0 == iRet)
    {
        printf("ERROR!\r\n");
        system("pause");
    }
}

void TestCase01()
{
    unsigned int size;
    CPPUNIT_ASSERT(0 == start_struct());
    CPPUNIT_ASSERT(0 == add_basic_type(INT_TYPE));
    CPPUNIT_ASSERT(0 == begin_nested_struct());
    CPPUNIT_ASSERT(0 == add_basic_type(SHORT_TYPE));
    CPPUNIT_ASSERT(0 == begin_nested_struct());
    CPPUNIT_ASSERT(0 == add_basic_type(DOUBLE_TYPE));
    CPPUNIT_ASSERT(0 == end_nested_struct());
    CPPUNIT_ASSERT(0 == end_nested_struct());
    CPPUNIT_ASSERT(0 == add_array(CHAR_TYPE, 2));
    CPPUNIT_ASSERT(0 == finish_struct(&size));
    CPPUNIT_ASSERT(size == 32);
    printf("TestCase01 Ok!\r\n");
}

void TestCase02()
{
    unsigned int size = 0;
    CPPUNIT_ASSERT(0 == start_struct());
    CPPUNIT_ASSERT(0 == add_basic_type(INT_TYPE));
    CPPUNIT_ASSERT(0 == add_basic_type(DOUBLE_TYPE));
    CPPUNIT_ASSERT(0 == add_basic_type(SHORT_TYPE));
    CPPUNIT_ASSERT(0 == add_array(CHAR_TYPE, 3));
    CPPUNIT_ASSERT(0 == finish_struct(&size));
    CPPUNIT_ASSERT(size == 24);
    printf("TestCase02 Ok!\r\n");
}

int _tmain(int argc, _TCHAR* argv[])
{
    TestCase01();
    TestCase02();
    return 0;
}
View Code
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM