Применение sizeof() к элементу в const char *array[]

#c

#c

Вопрос:

Это работает отлично:

 #include <unistd.h>

const char error[] = “Not enough argumentsn”;

int main(void)
{
    write(2, error, sizeof(error));
    return (0);
}

Output: Not enough arguments
  

Однако в этом случае sizeof возвращает размер указателя вместо:

 
#include <unistd.h>

const char *error[] = {
    "Not enough argumentsn",
    "Malloc failedn",
    "Etc...n",
    NULL
};

int main(void)
{
    int i = 0;

    while (error[i])
    {
        write(2, error[i], sizeof(error[i]));
        i  ;
    }
    return (0);
}

Output: Not enouMalloc fEtc...
  

Очевидно, я мог бы просто использовать strlen или printf или множество других решений. Но мне в основном интересно, выполнимо ли это с помощью sizeof(), но без явного объявления его размера (например, ошибка символа [4] [12]).

Комментарии:

1. Нет, это невозможно. Элементы error — это указатели, а не массивы.

2. Для первого примера: почти идеально, или 1 байт; sizeof(error) возвращает 22, покрывая показанный 21 байт массива нулевой терминатор; попробуйте передать вывод в cat -v или xxd -g 1

Ответ №1:

sizeof — это оператор (не функция), который вычисляет свой операнд во время компиляции, а не во время выполнения (за исключением случаев массивов переменной длины). char* Следовательно, вы получаете этот результат из-за типа элемента в массиве.

Обратите внимание, что существует исключение из ограничения времени компиляции для sizeof . C99 и Cxx11 позволяют вычислять sizeof во время выполнения для массивов переменной длины.

Комментарии:

1. Если sizeof вычисляется во время компиляции, как работает #include <stdio.h> / int main(void) {int n; scanf("%d", amp;n); int a[n]; printf("%zun", sizeof a); } ?

2. @EricPostpischil в c99 и cpp 11 есть исключение для массивов переменной длины.

3. Значит, он не всегда вычисляется во время компиляции?

Ответ №2:

Это возможно, но не просто. Вы можете определить структуру типа:

 struct error_st {
    char * msg;
    size_t msg_len;
}
  

Создайте макрос, подобный:

 #define ERROR(msg) {msg, sizeof(msg)}
  

Затем ваш список ошибок становится:

 struct error_st error_list[] = {
    ERROR("Not enough argumentsn"),
    ERROR("Malloc failedn"),
    ERROR("Etc...n"),
    {NULL, 0}
};
  

Использование:

 write(2, error_list[i].msg, error_list[i].msg_len);
  

Возможно, не стоит использовать дополнительную структуру и макрос, а также дополнительные поля, если вы никогда не собираетесь использовать их в другом месте. Вы можете сделать struct частью объявления, но я часто обнаруживаю, что в конечном итоге мне нужно его отделить, и у вас все еще остается этот дополнительный макрос:

 #define ERROR(msg) {msg, sizeof(msg)}
struct error_st {
    char * msg;
    size_t msg_len;
} error_list[] = {
    ERROR("Not enough argumentsn"),
    ERROR("Malloc failedn"),
    ERROR("Etc...n"),
    {NULL, 0}
};
  

Комментарии:

1. Аналогично первому примеру OP, sizeof() строковый литерал учитывает нулевой ограничитель; каждый write() вывод из этого примера будет содержать нулевой байт в конце; проверьте с cat -v помощью или xxd -g 1

2. Это супер умно, мне это нравится!

3. Вы правы. Это размер, который вам нужен для копирования, но не для записи. Вы могли бы изменить макрос, чтобы сохранить sizeof()-1 .