Моя проблема в том, что в зависимости от ОС мне нужно объявить массив, содержащий текст ошибки, но я не могу понять, как это реализовать с помощью файлов заголовков и директив препроцессора.
Я пробовал следующую реализацию, но не могу получить доступ к нужному массиву:
номер ошибки.c:
#include "s21_errorno.h"
#ifdef __linux__
os_error[] = {"",
"Operation not permitted",
"No such file or directory",
"No such process",
"Interrupted system call",
"I/O error",
"No such device or address",
"Argument list too long",
"Exec format error",
"Bad file number",
"No child processes"};
#elif __APPLE__
os_error[] = {"",
"Operation not permitted",
"No such file or directory",
"No such process",
"Interrupted system call",
"Input/output error",
"Device not configured",
"Argument list too long",
"Exec format error",
"Bad file descriptor",
"No child processes"};
#endif
номер ошибки.h:
#ifndef C2_S21_STRINGPLUS_0_S21_ERRORNO_H
#define C2_S21_STRINGPLUS_0_S21_ERRORNO_H
#define const char* os_error[]
#endif // C2_S21_STRINGPLUS_0_S21_ERRORNO_H
основной.с:
#include "stdio.h"
#include "s21_errorno.h"
int main() {
for (int i = 0; i < 50 ; ++i) {
printf("%s",os_error[i]);
}
return 0;
}
один из моих линуксовых макросов, так что это условие должно точно выполняться, проблема в том, что я не могу его правильно реализовать...
Я только что заметил в вашем заголовочном файле, что у вас есть #define const char* os_error[]. Это должно быть extern const char* os_error[];. Это должно решить проблему с компиляцией.
У меня может возникнуть соблазн выполнить дедупликацию, т.е. установить только значения, специфичные для платформы. +1 на внешнем, но разве вы не устанавливаете значение в заголовочном файле? Почему вы определяете вместо typedef?
Почему вы используете #ifdef в одном месте и #elif в другом вместо #if defined __linux__ и #elif defined __APPLE__ в обоих или #if __linux и #elif __APPLE__ в обоих? Что вы хотите, чтобы произошло, если __linux__ определено и равно нулю?





Вы можете определить такую переменную в файле errno.c, чтобы исключить дублирование:
const char *os_error[] = {
"",
"Operation not permitted",
"No such file or directory",
"No such process",
"Interrupted system call",
#ifdef __linux__
"I/O error",
"No such device or address",
#elif __APPLE__
"Input/output error",
"Device not configured",
#endif
"Argument list too long",
"Exec format error",
"Bad file number",
"No child processes"
};
size_t size_error = sizeof os_error / sizeof *os_error;
Соответствующее определение заголовка в errno.h будет таким:
#ifndef ERRORNO_H
#define ERRORNO_H
extern const char *os_error[];
extern size_t size_error;
#endif
Это не сработает, если вы включите файл заголовка в несколько исходных файлов, потому что компоновщик найдет символ, определенный несколько раз.
@CostantinoGrana Я добавлю охранников, чтобы уточнить ответ. Для меня это было очевидно.
Защита заголовка не помогает против множественных определений, она помогает только при множественных включениях. Полностью правильное решение должно разделять объявление (в заголовочном файле) и определение (в модуле перевода реализации), как показывает принятый ответ. Однако некоторые компоновщики допускают такие множественные определения и молча их игнорируют.
@thebusybee Спасибо, что написали это. На мой взгляд, препроцессор гарантирует, что компилятор увидит эту часть файла только один раз, но очевидно, что это не так. Обновленный ответ для хорошей меры.
Конечно, компилятор видит его только один раз. Но если вы включаете такой заголовок в несколько скомпилированных файлов, такая переменная определяется в каждой из единиц перевода. Компоновщик первым видит проблему. Вам нужно четко различать эти инструменты.
Начнем с заголовочного файла. Там нужна декларация: extern const char *os_error[];. Это позволяет вам использовать этот неполный массив указателей на символы в каждом файле .c, который его включает.
Затем в файле .c нужно определение: const char *os_error[] = { /*stuff*/ };
Но ваш os_error — неполный массив, поэтому вы не можете получить его размер с помощью sizeof. Вероятно, полезно также определить переменную size_error, чтобы сообщать о размере этого массива.
#ifndef S21_ERRORNO_H
#define S21_ERRORNO_H
#include <stdlib.h>
extern const char *os_error[];
extern size_t size_error;
#endif // S21_ERRORNO_H
#include "s21_errorno.h"
#ifdef __linux__
const char *os_error[] = { "",
"Operation not permitted",
"No such file or directory",
"No such process",
"Interrupted system call",
"I/O error",
"No such device or address",
"Argument list too long",
"Exec format error",
"Bad file number",
"No child processes" };
size_t size_error = sizeof os_error / sizeof *os_error;
#elif __APPLE__
const char *os_error[] = { "",
"Operation not permitted",
"No such file or directory",
"No such process",
"Interrupted system call",
"Input/output error",
"Device not configured",
"Argument list too long",
"Exec format error",
"Bad file descriptor",
"No child processes" };
size_t size_error = sizeof os_error / sizeof *os_error;
#endif
#include <stdio.h>
#include "s21_errorno.h"
int main(void)
{
for (size_t i = 0; i < size_error; ++i) {
printf("os_error[%d] = %s\n", i, os_error[i]);
}
return 0;
}
Вы не можете получить доступ к массиву на какой ОС? Я знаю, что clang установит макрос
__APPLE__на платформах Mac, я не уверен, что это установлено в Linux. Возможно, нужно добавить else в условие препроцессора, чтобы определить, не найдена ли ни одна из поддерживаемых систем?