Как определить массив в зависимости от ОС?

Моя проблема в том, что в зависимости от ОС мне нужно объявить массив, содержащий текст ошибки, но я не могу понять, как это реализовать с помощью файлов заголовков и директив препроцессора.

Я пробовал следующую реализацию, но не могу получить доступ к нужному массиву:

номер ошибки.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;
}

Вы не можете получить доступ к массиву на какой ОС? Я знаю, что clang установит макрос __APPLE__ на платформах Mac, я не уверен, что это установлено в Linux. Возможно, нужно добавить else в условие препроцессора, чтобы определить, не найдена ли ни одна из поддерживаемых систем?

beeselmane 11.12.2022 05:24

один из моих линуксовых макросов, так что это условие должно точно выполняться, проблема в том, что я не могу его правильно реализовать...

Flex1sh 11.12.2022 05:32

Я только что заметил в вашем заголовочном файле, что у вас есть #define const char* os_error[]. Это должно быть extern const char* os_error[];. Это должно решить проблему с компиляцией.

beeselmane 11.12.2022 05:33

У меня может возникнуть соблазн выполнить дедупликацию, т.е. установить только значения, специфичные для платформы. +1 на внешнем, но разве вы не устанавливаете значение в заголовочном файле? Почему вы определяете вместо typedef?

Allan Wind 11.12.2022 05:42

Почему вы используете #ifdef в одном месте и #elif в другом вместо #if defined __linux__ и #elif defined __APPLE__ в обоих или #if __linux и #elif __APPLE__ в обоих? Что вы хотите, чтобы произошло, если __linux__ определено и равно нулю?

Eric Postpischil 11.12.2022 12:21
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
5
93
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете определить такую ​​переменную в файле 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

Это не сработает, если вы включите файл заголовка в несколько исходных файлов, потому что компоновщик найдет символ, определенный несколько раз.

Costantino Grana 13.12.2022 18:03

@CostantinoGrana Я добавлю охранников, чтобы уточнить ответ. Для меня это было очевидно.

Allan Wind 20.12.2022 07:15

Защита заголовка не помогает против множественных определений, она помогает только при множественных включениях. Полностью правильное решение должно разделять объявление (в заголовочном файле) и определение (в модуле перевода реализации), как показывает принятый ответ. Однако некоторые компоновщики допускают такие множественные определения и молча их игнорируют.

the busybee 20.12.2022 09:11

@thebusybee Спасибо, что написали это. На мой взгляд, препроцессор гарантирует, что компилятор увидит эту часть файла только один раз, но очевидно, что это не так. Обновленный ответ для хорошей меры.

Allan Wind 20.12.2022 22:48

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

the busybee 21.12.2022 07:47
Ответ принят как подходящий

Начнем с заголовочного файла. Там нужна декларация: extern const char *os_error[];. Это позволяет вам использовать этот неполный массив указателей на символы в каждом файле .c, который его включает.

Затем в файле .c нужно определение: const char *os_error[] = { /*stuff*/ };

Но ваш os_error — неполный массив, поэтому вы не можете получить его размер с помощью sizeof. Вероятно, полезно также определить переменную size_error, чтобы сообщать о размере этого массива.

s21_errorno.h:

#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

s21_errorno.c:

#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;
}

Другие вопросы по теме