#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 .