2017-02-18 62 views
9

Tworzę aplikację wielosystemową. Wykorzystuje na przykład funkcję itoa, która jest zaimplementowana w niektórych systemach, ale nie we wszystkich. Gdybym po prostu dostarczyć własną itoa realizacji:Sprawdź, czy system implementuje funkcję

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); 

wiem, że mogę sprawdzić, czy makra są predefiniowane i zdefiniować je, jeśli nie:

#ifndef _SOME_MACRO 
#define _SOME_MACRO 45 
#endif 

Czy istnieje sposób, aby sprawdzić, czy funkcja C jest wstępnie -implementowany, a jeśli nie, wdrożyć go? Lub po prostu zrezygnować z funkcji?

+12

Istnieje system 'autoconf' - zaprojektowany do radzenia sobie z takimi złożonościami. Nie ma wielu prostszych systemów, które działają niezawodnie; Nie jestem pewien, czy znam jednego. Istnieją również 'automake' i' libtool', które działają w połączeniu z 'autoconf', ale najczęściej używasz' autoconf'. Można zbadać inne systemy kompilacji, takie jak 'cmake'. –

+2

Inną trudną częścią dotyczącą funkcji, która jest dostępna tylko w systemach _some_ jest to, że są one zbyt często _funkcjonalnie różne_ w różnych systemach. Proponuję funkcję otoki. – chux

+0

Funkcja @chux * wrapper * objaśnienie? –

Odpowiedz

4

Zakładam używasz GCC, jak widzę MinGW na swojej drodze ... Jest tylko jeden sposób łącznik może GNU zaopiekuj się tym dla ciebie. Więc nie wiesz, czy istnieje implementacja itoa, czy nie. Spróbuj tego:

Utwórz nowy plik (bez żadnych nagłówków) nazywa my_itoa.c:

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

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

Teraz utworzyć inny plik, impl_itoa.c. Tutaj wpisz realizację itoa jednak dodać słabą Alias:

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

skompilować wszystkie pliki z impl_itoa.c na końcu.

W ten sposób, jeśli itoa nie jest dostępna w bibliotece standardowej, ta zostanie połączona. Możesz mieć pewność, że to kompiluje, czy jest ona dostępna.

+0

Nie działa. Dostaję 'przeniesienie skrócone do rozmiaru: R_X86_64_PC32 z niezdefiniowanym symbolem 'itoa'' –

+0

@MDXF czy możesz potwierdzić, czy interesuje Cię tylko MinGW? To jest dobra sugestia, niestety MinGW jej nie obsługuje, – jerry

+0

Cóż, wydaje się to najlepsze. Dzięki. Przyjmie i nagrodzi, jeśli nie pojawi się lepsze rozwiązanie. –

6

Biorąc pod uwagę, że napisano już własną implementację itoa(), polecam zmienić jej nazwę i używać jej wszędzie. Przynajmniej jesteś pewien, że zachowujesz się tak samo na wszystkich platformach i unikasz problemu z łączeniem.

Nie zapomnij wyjaśnić swój wybór w komentarzach kodu ...

2

Ajay Brahmakshatriya's suggestion jest dobry, ale niestety MinGW nie obsługuje słabej definicji ostatnio sprawdziłem (patrz np. https://groups.google.com/forum/#!topic/mingwusers/44B4QMPo8lQ).

Jednak uważam, że słabe referencje działają w MinGW. Weź ten minimalny przykład:

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

Jeśli system zapewnia implementację itoa, który ma zostać użyty, a wynik byłby

str: 10

przeciwnym razie dostaniesz

str: no itoa

+0

http://imgur.com/a/TdlOP –

+0

@MDXF, więc widzisz, że działa przez cmd, ale nie przez cygwin? Może być różnica wersji (jestem na "gcc 4.9.3"), ale działa na moim systemie przez co najmniej cygwin. A przez "dzieła" mam na myśli linki i wypisuję 'str: no itoa'. – jerry

+0

@MDXF Właśnie zaktualizowałem cygwin (z gcc version 5.4.0) i przetestowałem natywną MinGW, działa zarówno na moim systemie. Jakiej wersji używasz? Czy to 32 czy 64-bitowe? – jerry

0

Istnieją dwa bardzo ważne punkty warte dokonywania związanych tutaj wzdłuż „nie rób tego w ten sposób” linii:

  • Nie używają atoi ponieważ it's not safe.
  • Nie używaj atoi, ponieważ nie jest to funkcja standardowa i istnieją dobre standardowe funkcje (takie jak snprintf), które można wykonywać w dowolny sposób.

Ale, odkładając to na chwilę, chcę przedstawić Wam autoconf, part of the GNU build system. autoconf jest częścią bardzo wszechstronnego, bardzo przenośnego zestawu narzędzi, które mają na celu ułatwienie pisania kodu, który można z powodzeniem zbudować na szerokiej gamie systemów docelowych. Niektórzy twierdzą, że autoconf jest zbyt skomplikowanym systemem, który rozwiązuje tylko jeden problem, który stwarzasz za pomocą tylko jednej funkcji bibliotecznej, ale jak każdy program rośnie, najprawdopodobniej będzie musiał stawić czoła kolejnym przeszkodom podobnym do tego, a ustawienie autoconfu dla twojego programu będzie teraz jesteś w znacznie silniejszej pozycji na przyszłość.

start z pliku o nazwie Makefile.in który zawiera:

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

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

clean: 
    rm -f program.o program 

i plik o nazwie configure.ac który zawiera:

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 

i plik o nazwie program.c który zawiera:

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

Teraz uruchom kolejno następujące polecenia:

  1. autoheader: To generuje nowy plik o nazwie config.h.in których będziemy potrzebować później.
  2. autoconf: To generuje skrypt konfiguracyjny o nazwie configure
  3. ./configure: To działa kilka testów, w tym kontroli, które masz pracy kompilatora C i, ponieważ prosiliśmy go, czy dana funkcja jest dostępna itoa. Zapisuje wyniki w pliku config.h na później.
  4. make: To kompiluje i łączy program.
  5. ./program: To w końcu uruchamia program.

Podczas etapu ./configure zobaczysz sporo produkcji, w tym coś takiego:

checking for itoa... no 

W tym przypadku, zobaczysz, że config.h znalezisko zawiera następujące wiersze:

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

Ewentualnie, jeśli zrobić mieć atoi dostępne, zobaczysz:

checking for itoa... yes 

i to w config.h:

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

Zobaczysz, że program może teraz odczytać nagłówek config.h i wybierz zdefiniować itoa jeśli nie jest obecny.

Tak, daleko jest do rozwiązania problemu, ale teraz zaczęto używać bardzo potężnego narzędzia, które może pomóc na wiele sposobów.

Powodzenia!

Powiązane problemy