Как включить 4-символьную строку в C? - PullRequest
2 голосов
/ 11 ноября 2011

Мне нужно переключиться на основе 4-символьной строки. Я поместил строку в объединение, чтобы я мог по крайней мере сослаться на нее как на 32-разрядное целое число.

union
{
    int32u  integer;
    char    string[4];
}software_version;

Но теперь я не знаю, что написать в заявлениях по делу. Мне нужен какой-то макрос, чтобы преобразовать 4-символьный строковый литерал в целое число. Е.Г.

#define STRING_TO_INTEGER(s)    ?? What goes here ??
#define VERSION_2_3_7           STRING_TO_INTEGER("0237")
#define VERSION_2_4_1           STRING_TO_INTEGER("0241")

switch (array[i].software_version.integer)
{
    case VERSION_2_3_7:
        break;

    case VERSION_2_4_1:
        break;
}

Есть ли способ сделать макрос STRING_TO_INTEGER (). Или есть лучший способ справиться с переключателем?

Ответы [ 4 ]

7 голосов
/ 11 ноября 2011

Портативный пример кода:

#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>

#define CHARS_TO_U32(c1, c2, c3, c4) (((uint32_t)(uint8_t)(c1) | \
    (uint32_t)(uint8_t)(c2) << 8 | (uint32_t)(uint8_t)(c3) << 16 | \
    (uint32_t)(uint8_t)(c4) << 24))

static inline uint32_t string_to_u32(const char *string)
{
    assert(strlen(string) >= 4);
    return CHARS_TO_U32(string[0], string[1], string[2], string[3]);
}

#define VERSION_2_3_7 CHARS_TO_U32('0', '2', '3', '7')
#define VERSION_2_4_1 CHARS_TO_U32('0', '2', '4', '1')

int main(int argc, char *argv[])
{
    assert(argc == 2);
    switch(string_to_u32(argv[1]))
    {
        case VERSION_2_3_7:
        case VERSION_2_4_1:
        puts("supported version");
        return 0;

        default:
        puts("unsupported version");
        return 1;
    }
}

Код предполагает только существование целочисленных типов uint8_t и uint32_t и не зависит от ширины и подписи типа char, а также от порядкового номера. Он свободен от коллизий, если кодировка символов использует только значения в диапазоне uint8_t.

2 голосов
/ 11 ноября 2011

Вы включаете четырехсимвольные коды, подобные этому

switch (fourcc) {
case 'FROB':
}

Обратите внимание на разницу: "XXXX" - это строка, 'XXXX' - это символ / целочисленный литерал.

Однако я бы предложил вам использовать вместо этого отдельные номера версий, например ::100100

struct Version {
    int major, minor, patch;
};

bool smaller (Version lhs, Version rhs) {
    if (lhs.major < rhs.major) return true;
    if (lhs.major > rhs.major) return false;
    if (lhs.minor < rhs.minor) return true;
    if (lhs.minor > rhs.minor) return false;
    if (lhs.patch < rhs.patch) return true;
    if (lhs.patch > rhs.patch) return false; // redundant, for readabiltiy

    return false; // equal
}
0 голосов
/ 11 ноября 2011
int versionstring_to_int(char * str)
{
char temp [ 1+ sizeof software_version.string ]; /* typically 1+4 */

if (!str || ! *str) return -1;
memcpy (temp, str, sizeof temp -1);
temp [sizeof temp -1] = 0;

return atoi (temp );
}

РЕДАКТИРОВАТЬ:

#define STRING_TO_INTEGER(s)    versionstring_to_int(s)
#define VERSION_2_3_7           237
#define VERSION_2_4_1           241

switch ( STRING_TO_INTEGER( array[i].software_version.string) )
{
case VERSION_2_3_7:
    break;

case VERSION_2_4_1:
    break;
}
0 голосов
/ 11 ноября 2011

Обновлено:

#define VERSION_2_3_7 '0237'
...