Проверьте, реализует ли система функцию

Я создаю кросс-системное приложение. Он использует, например, функцию itoa, который реализован на некоторых системах, но не на всех. Если я просто предоставлю свой itoa реализация:

header.h:115:13: error: conflicting types for 'itoa'
 extern void itoa(int, char[]);

In file included from header.h:2:0,
                 from file.c:2:0,
c:\path\to\mingw\include\stdlib.h:631:40: note: previous declaration of 'itoa' was here
 _CRTIMP __cdecl __MINGW_NOTHROW  char* itoa (int, char*, int);

Я знаю, что могу проверить, предопределены ли макросы, и определить их, если нет:

#ifndef _SOME_MACRO
#define _SOME_MACRO 45
#endif

Есть ли способ проверить, предварительно ли реализована функция C, и если нет, реализовать ее? Или просто отключить функцию?

4 ответа

Решение

Я предполагаю, что вы используете GCC, поскольку я вижу MinGW на вашем пути... есть один способ, которым линкер GNU может позаботиться об этом за вас. Таким образом, вы не знаете, есть ли itoa реализация или нет. Попробуй это:

Создайте новый файл (без заголовков) с именем my_itoa.c:

char *itoa (int, char *, int);

char *my_itoa (int a, char *b, int c)
{
    return itoa(a, b, c);
}

Теперь создайте другой файл, impl_itoa.c, Здесь напишите реализацию itoa но добавьте слабый псевдоним:

char* __attribute__ ((weak)) itoa(int a, char *b, int c)
{
     // implementation here
}

Скомпилируйте все файлы с impl_itoa.c в конце.

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

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

Не забудьте объяснить свой выбор в комментариях к вашему коду...

Предложение Аджая Брахмакшатрии является хорошим, но, к сожалению, MinGW не поддерживает слабое определение, которое я проверял в последний раз (см., Например, https://groups.google.com/forum/).

Тем не менее, я считаю, что слабые ссылки работают в MinGW. Возьмите этот минимальный пример:

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

__attribute__ ((weak)) char* itoa (int, char*, int);

char* my_itoa (int a, char* b, int c)
{
    if(itoa != NULL) {
        return itoa(a, b, c);
    } else {
        // toy implementation for demo purposes
        // replace with your own implementation
        strcpy(b, "no itoa");
        return b;
    }        
}

int main()
{
    char *str = malloc((sizeof(int)*3+1));

    my_itoa(10, str, 10);
    printf("str: %s\n", str);
    return 0;
}

Если система обеспечивает itoa реализация, которая должна быть использована, и результат будет

ул: 10

В противном случае вы получите

ул: нет итоа

Здесь есть два действительно важных аспекта, которые стоит упомянуть по принципу "не делай так":

  • Не использовать atoi потому что это не безопасно.
  • Не использовать atoi потому что это не стандартная функция, и есть хорошие стандартные функции (такие как snprintf) которые доступны, чтобы делать то, что вы хотите.

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

Начните с файла с именем Makefile.in который содержит:

CFLAGS=--ansi --pedantic -Wall -W

program: program.o
program.o: program.c

clean:
  rm -f program.o program

и файл с именем configure.ac который содержит:

AC_PREREQ([2.69])
AC_INIT(program, 1.0)
AC_CONFIG_SRCDIR([program.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for library functions.
AH_TEMPLATE([HAVE_ITOA], [Set to 1 if function atoi() is available.])
AC_CHECK_FUNC([itoa],
              [AC_DEFINE([HAVE_ITOA], [1])]
              )

AC_CONFIG_FILES([Makefile])
AC_OUTPUT

и файл с именем program.c который содержит:

#include <stdio.h>
#include "config.h"

#ifndef HAVE_ITOA

/*
 * WARNING: This code is for demonstration purposes only. Your
 * implementation must have a way of ensuring that the size of the string
 * produced does not overflow the buffer provided.
 */

void itoa(int n, char* p) {
  sprintf(p, "%d", n);
}
#endif

int main(void) {
  char buffer[100];
  itoa(10, buffer);
  printf("Result: %s\n", buffer);
  return 0;
}

Теперь по очереди выполните следующие команды:

  1. autoheader: Это создает новый файл с именем config.h.in который нам понадобится позже.
  2. autoconf: Генерируется скрипт конфигурации с именем configure
  3. ./configure: Это запускает некоторые тесты, включая проверку того, что у вас есть работающий компилятор C и, потому что мы спросили его, является ли itoa функция доступна. Записывает свои результаты в файл config.h Для последующего.
  4. make: Это компилирует и связывает программу.
  5. ./program: Это, наконец, запускает программу.

В течение ./configure шаг, вы увидите довольно много продукции, в том числе что-то вроде:

checking for itoa... no

В этом случае вы увидите, что config.h find содержит следующие строки:

/* Set to 1 if function atoi() is available. */
/* #undef HAVE_ITOA */

В качестве альтернативы, если у вас есть atoi доступно, вы увидите:

checking for itoa... yes

и это в config.h:

/* Set to 1 if function atoi() is available. */
#define HAVE_ITOA 1

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

Да, для решения вашей проблемы далеко, но вы начали использовать очень мощный инструмент, который может помочь вам множеством способов.

Удачи!

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