首页 > 解决方案 > 在C中通过引用定义数组元素

问题描述

我正在重写一个迭代二维数组的函数(它有效,所以我显然很想打破它)。该函数将为给定键的内容读取 INI 文件,并将返回的值存储到变量或将默认值存储到变量(在我的结构中,变量通过引用定义为 *pStoreToRef)。

支持在我的二维数组中存储默认值被证明是困难的。必须适应所有数据类型。怎么做?

二维数组由以下结构类型化:

typedef struct s_defaults {
    char        *cKeyTitle;
    uint16_t    nItemNr;
    uint8_t     nVarType;
    int         *pDefaultValue;
    uint16_t    nVarLength;
    uint8_t     nVarFloatDecimals;
    char        *pFormatString;
    int         *pStoreToRef;
    int         nNextItem;  // set to -1 at end
} site_defaults_t;

这是初始化程序:

site_defaults_t site_defaults[] =
{
    {"AUTOTUN_TOTAL_CYCLES\0",          SD_AUTORUN_TOTAL_CYCLES,            VT_INTEGER, 192,                            5,  0,  "%i\0",     (int*)&aAutoRunControl.nTotalCycles,1},
    {"AUTORUN_TEST_INTERVAL\0",         SD_AUTORUN_TEST_INTERVAL,           VT_INTEGER, 60,                             5,  0,  "%i\0",     (int*)&aAutoRunControl.nTestIntervalSecs,2},
    {"AUTORUN_TEST_LEN_SECS\0",         SD_AUTORUN_TEST_LEN_SECS,           VT_INTEGER, 30,                             6,  0,  "%i\0",     (int*)&aAutoRunControl.nTestLengthSecs,3},
    {"AUTORUN_TEST_FAN_SPEED\0",        SD_AUTORUN_TEST_FAN_SPEED,          VT_INTEGER, 85,                             3,  0,  "%i\0",     (int*)&aAutoRunControl.nSpeed,4},
    {"AUTORUN_TEST_PLATE_VOLTS\0",      SD_AUTORUN_TEST_PLATE_VOLTS,        VT_FLOAT,   40,                             3,  1,  "%2.1f\0",  (int*)&aAutoRunControl.vPlate,5},
    {"AUTORUN_TEST_SAMPLES_PER_SEC\0",  SD_AUTORUN_TEST_SAMPLES_PER_SEC,    VT_INTEGER, 10,                             2,  0,  "%i\0",     (int*)&aAutoRunControl.nSamplesPerSecond,6},
    {"SEND_FILES_FREQUENCY\0",          SD_SEND_FILES_FREQUENCY,            VT_INTEGER, 10,                             6,  0,  "%i\0",     (int*)&oSystemInfo.nSendFilesFrequency,7},
    {"POWER_60_HZ\0",                   SD_POWER_60_HZ,                     VT_BOOLEAN, true,                           1,  0,  "%i\0",     (int*)&aSystemState.Power60Hz,8},
    {"UPLOAD_ON_BOOT\0",                SD_UPLOAD_ON_BOOT,                  VT_BOOLEAN, false,                          1,  0,  "%i\0",     (int*)&oSystemInfo.EnableSendFilesOnBoot,9},
    {"AUTORUN_SENDFILES\0",             SD_AUTORUN_SENDFILES,               VT_BOOLEAN, true,                           1,  0,  "%i\0",     (int*)&aAutoRunControl.sendFiles,10},
    {"PREAMP_TRIM\0",                   SD_PREAMP_TRIM,                     VT_FLOAT,   0,                              3,  1,  "%2.1f\0",  (int*)&aSystemState.nPreampTrim,11},
    {"AUTORUN_PCIL_CONVERSION_CONST\0", SD_AUTORUN_PCIL_CONVERSION_CONST,   VT_FLOAT,   0.07608,                        2,  8,  "%2.8f\0",  (int*)&aAutoRunControl.pcilMult,12},
    {"ENABLE_DVDT_BEEP\0",              SD_ENABLE_DVDT_BEEP,                VT_BOOLEAN, false,                          1,  0,  "%i\0",     (int*)&oSystemInfo.AllowDvDtBeep,13},
    {"AUTORUN_PCIL_CONVERSION_ADJUST\0",SD_AUTORUN_PCIL_CONVERSION_ADJUST,  VT_FLOAT,   0.02,                           2,  8,  "%2.8f\0",  (int*)&aAutoRunControl.pcilMultAdjust,14},
    {"AUTORUN_DEMO_DURATION\0",         SD_AUTORUN_DEMO_DURATION,           VT_INTEGER, 30,                             5,  0,  "%i\0",     (int*)&aAutoRunControl.nDemoDuration,-1},
};

新字段,int *pDefaultValue;被证明是有问题的。我的理论是存储对值的引用,并且以这种方式存储的 pDefaultValue 可以是任何类型。如果要存储的默认值可以引用到地址,那应该可以工作,但在这种情况下呢?

关于解决方法的任何想法?

标签: cvariablesstructuretyped

解决方案


这是许多可能的解决方案之一。由于您使用 VARIANT 来描述信息,所以让我们使用 VARIANT。

为了清楚起见,我已经删除了其他结构成员,因为这完全是关于初始化 VARIANT 并且在这种情况下无关紧要。

首先是这个例子的增强结构:

typedef struct SiteMeta {
    char* name;
    VARIANT v;       
};

定义一个函数来初始化一个 VARIANT。

VARIANT VariantValInit(const VARTYPE vt, const void* value) {
    VARIANT v;
    VariantInit(&v);
    v.vt = vt;
    switch (vt) {
    case VT_I4:
        v.intVal = (int)value;
        break;
    case VT_BOOL:
        v.boolVal = (bool)value;
        break;
    default:
        // throw or something.
        break;
    }
    return v;
}

当然,上面的功能需要额外的案例来支持其他类型。

现在像这样声明你的默认值:

SiteMeta site_defaults[] =
{
    { "AUTOTUN_TOTAL_CYCLES", VariantValInit(VT_I4, (void*)192) },
    {"POWER_60_HZ", VariantValInit(VT_BOOL, (void*)true) }
};

推荐阅读