C - sizeof () на статических символьных массивах внутри структуры - невозможно? - PullRequest
0 голосов
/ 24 июля 2011

Мне нужно хранить два элемента для каждого элемента массива & mdash; два массива char, которые могут содержать нулевые байты & mdash; а затем все еще сможете использовать sizeof(), чтобы получить их длину. Поскольку эти значения не изменятся во время выполнения, я думаю, что GCC должен справиться с этим.

Вот код:

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

struct name_data {
    char *name;
    char *data;
} name_bins [] = {
    { "John", "\xAA\xAA\x00\xAA" },
    { "Mark", "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05" },
};

char bin_test[] = "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05";

int main () {
    printf("sizeof(bin_test) = %lu\n", sizeof(bin_test));
    printf("sizeof(name_bins[1].data) = %lu\n", sizeof(name_bins[1].data));
    exit(0);
}

Вывод этого кода:

sizeof(bin_test) = 11
sizeof(name_bins[1].data) = 8

Однако bin_test эквивалентно name_bins[1].data по содержанию & mdash; хотя определение типа отличается & mdash; bin_test - это char[], а names_bins[1].data - это char*.

Есть ли способ определить массив name_bins вместо char[] s? Есть ли способ заставить GCC распознавать эти значения как статические константы и возвращать реальный размер контента с помощью sizeof() & mdash; который он уже вычисляет во время компиляции?

Ответы [ 3 ]

2 голосов
/ 24 июля 2011

Нет, это невозможно. Размер struct постоянен (sizeof любой объект name_data всегда одинаков). Если бы это было возможно, вы могли бы иметь два объекта одного типа с разными размерами.

1 голос
/ 24 июля 2011

Вы можете почти делать то, что вы хотите, сохраняя размер data как отдельную запись:

struct name_data {
    char  *name;
    char  *data;
    size_t data_size;
} name_bins[] = {
    {
        "John",
        "\xAA\xAA\x00\xAA",
        sizeof("\xAA\xAA\x00\xAA")
     }, {
         "Mark",
         "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05",
         sizeof("\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05")
     }
};

А затем:

printf("sizeof(bin_test) = %lu\n", sizeof(bin_test));
printf("sizeof(name_bins[1].data) = %lu\n", (unsigned long)name_bins[1].data_size);

Тогда вы просточтобы убедиться, что ваша name_bins инициализация была правильной.Вы можете бросить макрос в миксе, чтобы избежать повторения:

#define BIN(x,y) { (x), (y), sizeof(y) }

struct name_data {
    char  *name;
    char  *data;
    size_t data_size;
} name_bins [] = {
    BIN("John", "\xAA\xAA\x00\xAA"),
    BIN("Mark", "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05")
};
1 голос
/ 24 июля 2011

Если немного подумать о том, что вы просите компилятора сделать здесь, вы, вероятно, поймете, что то, что вы просите, нереально.

Чтобы компилятор выяснил, что sizeof(name_bins[1].data) равен 11, он должен убедиться, что каждый возможный путь, ведущий к строке кода, содержащей sizeof, имеет точно такое же состояние, когда он приходит к name_bins[1].data объекту.

В приведенном вами простом примере вы можете ожидать, что компилятор сможет каким-то образом это выяснить. Но что, если ваше приложение станет более сложным? Как компилятор узнает, что name_bins[1].data все еще содержит "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05"?

РЕДАКТИРОВАТЬ : Следуя комментариям, вы можете создать новый тип, который будет содержать как данные, так и размер:

typedef struct ConstByteString {
    const unsigned char* data;
    size_t length;
} ConstByteString;

, а затем используйте это:

struct name_data {
    const char* name;
    ConstByteString data;
} name_bins [] = {
    { "John", { "\xAA\xAA\x00\xAA", sizeof("\xAA\xAA\x00\xAA") } },
    { "Mark", { "\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05", sizeof("\xFF\x0A\x00\x33\x01\x01\x03\x04\x04\x05") } },
};
...