C++ std:: constructs in static library used by C program

Started by
12 comments, last by Koshmaar 18 years, 8 months ago
OMG, I'm dead!!! [bawling]


Hehe, just kidding ;-) There's #define CFG_String std::string, so changing only one line should suffice. Of course, assuming that I understood you correctly - change std::string to my own basic_string typedef with own allocator, recompile everything... and voila!


Btw, of course you are right, first I thought that those errors are both in std::string and std::map, but after examining all errors, it looks that maps are ok.


Quote:
as you are using a GCC compiler already you can just use __gnu_cxx::malloc_allocator in header ext/malloc_allocator.h as you can probably tell its uses malloc/free for allocation/deallocation instead but remember its not part of the standard its a GCC library extension so its trivial to define your own if you want.


Hmmm, there's no malloc_allocator.h in my MinGW 3.5(not standard GCC, I'm compiling on Win) compiler. Maybe I'm using (too) old version?
Anyway, you mentioned that its trivial to implement such allocator. I have in GPG #3 chapter about writing STL allocators, but anyway I'd like to see other examples (if you have any :-) ).


---

Btw, if any idiot ever said that error messagess in MinGW are user friendly... this snippet is for him:

(.text$_ZNSt14__simple_allocISt13_Rb_tree_nodeISt4pairIKSs18CFG_Internal_GroupEESt24__default_alloc_templateILb1ELi0EEE8allocateEj+0x2c):SDL_config.c: undefined reference to `std::__default_alloc_template<true, 0>::allocate(unsigned)'(.text$_ZNSt8_Rb_treeISsSt4pairIKSs18CFG_Internal_EntryESt10_Select1stIS3_ESt4lessISsESaIS3_EE14_M_create_nodeERKS3_+0x6f):SDL_config.c: undefined reference to `__cxa_begin_catch'(.text$_ZNSt8_Rb_treeISsSt4pairIKSs18CFG_Internal_EntryESt10_Select1stIS3_ESt4lessISsESaIS3_EE14_M_create_nodeERKS3_+0x8d):SDL_config.c: undefined reference to `__cxa_rethrow'(.text$_ZNSt8_Rb_treeISsSt4pairIKSs18CFG_Internal_EntryESt10_Select1stIS3_ESt4lessISsESaIS3_EE14_M_create_nodeERKS3_+0xb0):SDL_config.c: undefined reference to `__cxa_end_catch'(.text$_ZSt10_ConstructISt4pairIKSs18CFG_Internal_EntryES3_EvPT_RKT0_+0xc):SDL_config.c: undefined reference to `__gxx_personality_sj0'(.text$_ZStltIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_ES8_+0x14):SDL_config.c: undefined reference to `std::string::compare(std::string const&) const'


That's exactly the same what snk_kid said post above, the only differenc is that's in compiler's language... ;-)
Advertisement
Quote:Original post by Koshmaar
Hmmm, there's no malloc_allocator.h in my MinGW 3.5(not standard GCC, I'm compiling on Win) compiler. Maybe I'm using (too) old version?
Anyway, you mentioned that its trivial to implement such allocator. I have in GPG #3 chapter about writing STL allocators, but anyway I'd like to see other examples (if you have any :-) ).


You could always update it [wink] if not here is an exact copy of the file:

// Allocator that wraps "C" malloc -*- C++ -*-// Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.//// This file is part of the GNU ISO C++ Library.  This library is free// software; you can redistribute it and/or modify it under the// terms of the GNU General Public License as published by the// Free Software Foundation; either version 2, or (at your option)// any later version.// This library is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.// You should have received a copy of the GNU General Public License along// with this library; see the file COPYING.  If not, write to the Free// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,// USA.// As a special exception, you may use this file as part of a free software// library without restriction.  Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License.  This exception does not however// invalidate any other reasons why the executable file might be covered by// the GNU General Public License.#ifndef _MALLOC_ALLOCATOR_H#define _MALLOC_ALLOCATOR_H 1#include <new>namespace __gnu_cxx{  /**   *  @brief  An allocator that uses malloc   *   *  This is precisely the allocator defined in the C++ Standard.    *    - all allocation calls malloc   *    - all deallocation calls free   *   *  (See @link Allocators allocators info @endlink for more.)   */  template<typename _Tp>    class malloc_allocator    {    public:      typedef size_t     size_type;      typedef ptrdiff_t  difference_type;      typedef _Tp*       pointer;      typedef const _Tp* const_pointer;      typedef _Tp&       reference;      typedef const _Tp& const_reference;      typedef _Tp        value_type;      template<typename _Tp1>        struct rebind        { typedef malloc_allocator<_Tp1> other; };      malloc_allocator() throw() { }      malloc_allocator(const malloc_allocator&) throw() { }      template<typename _Tp1>        malloc_allocator(const malloc_allocator<_Tp1>&) throw() { }      ~malloc_allocator() throw() { }      pointer      address(reference __x) const { return &__x; }      const_pointer      address(const_reference __x) const { return &__x; }      // NB: __n is permitted to be 0.  The C++ standard says nothing      // about what the return value is when __n == 0.      pointer      allocate(size_type __n, const void* = 0)      {	pointer __ret = static_cast<_Tp*>(malloc(__n * sizeof(_Tp)));	if (!__ret)	  throw std::bad_alloc();	return __ret;      }      // __p is not permitted to be a null pointer.      void      deallocate(pointer __p, size_type)      { free(static_cast<void*>(__p)); }      size_type      max_size() const throw()       { return size_t(-1) / sizeof(_Tp); }      // _GLIBCXX_RESOLVE_LIB_DEFECTS      // 402. wrong new expression in [some_] allocator::construct      void       construct(pointer __p, const _Tp& __val)       { ::new(__p) value_type(__val); }      void       destroy(pointer __p) { __p->~_Tp(); }    };  template<typename _Tp>    inline bool    operator==(const malloc_allocator<_Tp>&, const malloc_allocator<_Tp>&)    { return true; }    template<typename _Tp>    inline bool    operator!=(const malloc_allocator<_Tp>&, const malloc_allocator<_Tp>&)    { return false; }} // namespace __gnu_cxx#endif


Don't forget to include cstdlib where ever you use it.
Actually that idea will still lead to problems (i think), i've never tried this myself before but after some playing around using something like malloc_allocator wont be enough you will still come across problems. I figured out that you can still use things like std::allocator and operator new/delete but you will need to link with libstdc++ on GCC when you finally compile an executable e.g.:


foo.h
#ifndef STD_STRING_H#define STD_STRING_H#ifdef __cplusplusextern "C" {#endif#include <stddef.h>typedef struct std_string std_string;std_string* string_construct(const char* s);char string_at(std_string* s, size_t index);void string_destroy(std_string* s);#ifdef __cplusplus};#endif#endif



foo.cpp
#include "foo.h"#include <string>struct std_string {   std::string s;   std_string(const char* cs): s(cs) {}};std_string* string_construct(const char* c) {   return new std_string(c);}char string_at(std_string* ss, size_t index) {   return ss->s[index];}void string_destroy(std_string* s) {    delete s;}



main.c
#include "foo.h"#include <stdio.h>int main() {   std_string* s = string_construct("hello");   printf("%c%c%c", string_at(s, 0), string_at(s, 1), string_at(s, 2));   string_destroy(s);}



Compile & Run:
g++ -O3 foo.cpp -cgcc -std=c99 -O3 foo.o main.c -o test -lstdc++./testhel


whether or not you want a dependance on libstdc++ in C is another story...
Fortunately, I've managed to create static library project in VStudio, compile it, and then: successfully compile test programs BOTH in C++ and C.

What's strange, is that they compiled and linked WITHOUT specifing any additional allocators to std::string.

What's even more strange, is that test programs are working ;-) though sometimes there are crazy compiler errors in C version. Look at this code:

int main(int argc, char **argv) {  CFG_File config;  int result = CFG_OpenFile("test_001.cfg", &config );  /*if ( CFG_ERROR == result ) // (*)   {    fprintf(stderr, "Couldn't open file.");    return 1;   }  else if ( CFG_CRITICAL_ERROR == result )   {    fprintf(stderr, "Critical error: %s", CFG_GetError());    return 1;   }*/ // (**)    int value1 = CFG_ReadInt("screen_size_x", 101); (***) fprintf(stderr, "Integer value read from global group, entry *screen_size_x*: %i\n", value1 ); // (****) // ...


Above piece of code compiles and links without any problems, both in C and C++, on MinGW and VisualC++, with and without comments (*) and (**). However, when I remove comments from (*) and (**) and compile it in C on VisualC++, compiler complains:

(***) main.c(47) : error C2143: syntax error : missing ';' before 'type'(****) main.c(50) : error C2065: 'value1' : undeclared identifier


What's happening here? Even if I put ';' on closing '}', it still complains. BUT, if I copy n' paste lines (***) and (****) before first if, magically it's compiled without any problems... I don't what to think, probably it's trivial error connected with C syntax, which in this point differs with C++ and states that I should add sth here and there. Any thoughts?


---------

Ok, but enough this offtopic :-) let's go back to GCC. Snk_kid, I've done what you suggested: created malloc_allocator.h file with implementation you provided and added this code to library:

//#define CFG_GCC#ifdef CFG_GCC  #include <cstdlib>  #include <malloc_allocator.h>  #include <string>  typedef std::basic_string<char, std::char_traits<char>, __gnu_cxx::malloc_allocator<char> > CFG_Internal_String;  #define CFG_Internal_String_Arg const CFG_Internal_String &  #define CFG_String CFG_Internal_String#else  #define CFG_Internal_String_Arg const std::string &  #define CFG_String std::string#endif


When CFG_GCC is defined, if I compile library, I get problems with places, where any methods of CFG_Internal_String return std::string, and there is need to create from that returned string, new CFG_Internal_String. Hmmm, to be honest, it's actually only substr :-)

CFG_String groupName = parsed.substr(1, secondBracePos - 1);GCC says:error: conversion from `std::basic_string<char,    std::char_traits<char>, std::allocator<char> >' to non-scalar type `   std::basic_string<char, std::char_traits<char>,    __gnu_cxx::malloc_allocator<char> >' requestedVisual says:error C2440: 'initializing' : cannot convert from 'std::basic_string<_Elem,_Traits,_Ax>::_Myt' to 'std::basic_string<_Elem,_Traits,_Ax>'        with        [            _Elem=char,            _Traits=std::char_traits<char>,            _Ax=std::allocator<char>        ]        and        [            _Elem=char,            _Traits=std::char_traits<char>,            _Ax=__gnu_cxx::malloc_allocator<char>        ]        No constructor could take the source type, or constructor overload resolution was ambiguous


Well, quite logical. Substr() returns std::string, not const char * or even basic_string with allocator specified by user. Any ideas how to solve this problem? :-) If not, then on this site are listed functions that operate on std::string, especially copy, which copies string data to char array. Maybe after taking adress of begin() and sending it to copy, or playing with iterators, I could get it to work...


Btw, thanks for comments, snk_kid :-) sorry for no ++rating, but you were already maxed.

This topic is closed to new replies.

Advertisement