Проверьте, реализует ли система функцию
Я создаю кросс-системное приложение. Он использует, например, функцию 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;
}
Теперь по очереди выполните следующие команды:
autoheader
: Это создает новый файл с именемconfig.h.in
который нам понадобится позже.autoconf
: Генерируется скрипт конфигурации с именемconfigure
./configure
: Это запускает некоторые тесты, включая проверку того, что у вас есть работающий компилятор C и, потому что мы спросили его, является лиitoa
функция доступна. Записывает свои результаты в файлconfig.h
Для последующего.make
: Это компилирует и связывает программу../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
если это не присутствует.
Да, для решения вашей проблемы далеко, но вы начали использовать очень мощный инструмент, который может помочь вам множеством способов.
Удачи!