Home Php C# Sql C C++ Javascript Python Java Go Android Git Linux Asp.net Django .net Node.js Ios Xcode Cocoa Iphone Mysql Tomcat Mongodb Bash Objective-c Scala Visual-studio Apache Elasticsearch Jar Eclipse Jquery Ruby-on-rails Ruby Rubygems Android-studio Spring Lua Sqlite Emacs Ubuntu Perl Docker Swift Amazon-web-services Svn Html Ajax Xml Java-ee Maven Intellij-idea Rvm Macos Unix Css Ipad Postgresql Css3 Json Windows-server Vue.js Typescript Oracle Hibernate Internet-explorer Github Tensorflow Laravel Symfony Redis Html5 Google-app-engine Nginx Firefox Sqlalchemy Lucene Erlang Flask Vim Solr Webview Facebook Zend-framework Virtualenv Nosql Ide Twitter Safari Flutter Bundle Phonegap Centos Sphinx Actionscript Tornado Register | Login | Edit Tags | New Questions | 繁体 | 简体


10 questions online user: 28

134
votes
answers
15 views
+10

Using Boost to read and write XML files

Is there any good way (and a simple way too) using Boost to read and write XML files?

I can't seem to find any simple sample to read XML files using Boost. Can you point me a simple sample that uses Boost for reading and writing XML files?

If not Boost, is there any good and simple library to read and write XML files that you can recommend? (it must be a C++ library)

up vote 63 down vote accepted favorite
沙发
+630
+50

You should Try pugixml Light-weight, simple and fast XML parser for C++

The nicest thing about pugixml is the XPath support, which TinyXML and RapidXML lack.

Quoting RapidXML's author "I would like to thank Arseny Kapoulkine for his work on pugixml, which was an inspiration for this project" and "5% - 30% faster than pugixml, the fastest XML parser I know of" He had tested against version 0.3 of pugixml, which has reached recently version 0.42.

Here is an excerpt from pugixml documentation:

The main features are:

  • low memory consumption and fragmentation (the win over pugxml is ~1.3 times, TinyXML - ~2.5 times, Xerces (DOM) - ~4.3 times 1). Exact numbers can be seen in Comparison with existing parsers section.
  • extremely high parsing speed (the win over pugxml is ~6 times, TinyXML - ~10 times, Xerces-DOM - ~17.6 times 1
  • extremely high parsing speed (well, I'm repeating myself, but it's so fast, that it outperforms Expat by 2.8 times on test XML) 2
  • more or less standard-conformant (it will parse any standard-compliant file correctly, with the exception of DTD related issues)
  • pretty much error-ignorant (it will not choke on something like You & Me, like expat will; it will parse files with data in wrong encoding; and so on)
  • clean interface (a heavily refactored pugxml's one)
  • more or less Unicode-aware (actually, it assumes UTF-8 encoding of the input data, though it will readily work with ANSI - no UTF-16 for now (see Future work), with helper conversion functions (UTF-8 <-> UTF-16/32 (whatever is the default for std::wstring & wchar_t))
  • fully standard compliant C++ code (approved by Comeau strict mode); the library is multiplatform (see reference for platforms list)
  • high flexibility. You can control many aspects of file parsing and DOM tree building via parsing options.

Okay, you might ask - what's the catch? Everything is so cute - it's small, fast, robust, clean solution for parsing XML. What is missing? Ok, we are fair developers - so here is a misfeature list:

  • memory consumption. It beats every DOM-based parser that I know of - but when SAX parser comes, there is no chance. You can't process a 2 Gb XML file with less than 4 Gb of memory - and do it fast. Though pugixml behaves better, than all other DOM-based parser, so if you're stuck with DOM, it's not a problem.
  • memory consumption. Ok, I'm repeating myself. Again. When other parsers will allow you to provide XML file in a constant storage (or even as a memory mapped area), pugixml will not. So you'll have to copy the entire data into a non-constant storage. Moreover, it should persist during the parser's lifetime (the reasons for that and more about lifetimes is written below). Again, if you're ok with DOM - it should not be a problem, because the overall memory consumption is less (well, though you'll need a contiguous chunk of memory, which can be a problem).
  • lack of validation, DTD processing, XML namespaces, proper handling of encoding. If you need those - go take MSXML or XercesC or anything like that.

pugixml現在有UTF-8,UTF-16,UTF-32解析。 - Brent Arias 2011年4月6日23:47

@CristianAdam我無法弄清楚它是否支持SAX解析或它不支持...我認為它確實存在,因為你說它無法處理內存小於4GiB的2GiB XML文件。 - Kiril 4月9日在17:35

TinyXpath確實為TinyXML添加了xpath支持 - Aman Aggarwal 2014年6月3日6:23

@fizzbuzz這是真的,但根據TinyXPath文檔,“在Linux下,還沒有庫”。只有命令行工具。 - Scott Deerwester 2015年12月7日19:35

pugixml很好,但這不能回答有關Boost的問題? - Adrian Maire 17年10月16日7:47

+230

TinyXML is probably a good choice. As for Boost:

There is the Property_Tree library in the Boost Repository. It has been accepted, but support seems to be lacking at the moment (EDIT: Property_Tree is now part of Boost since version 1.41, read the documentation regarding its XML functionality).

Daniel Nuffer has implemented an xml parser for Boost Spirit.

此外,使用TinyXpath和TinyXML - Aman Aggarwal 2014年6月3日6:23

+160

There's also TinyXML, which is a nice and small C++ library. If you are looking for a lower-level library, RapidXML is a great starting point.

此外,使用TinyXpath與TinyXML - Aman Aggarwal於12月23日12:53

+100

Boost uses RapidXML as described in chapter XML Parser of page How to Populate a Property Tree:

Unfortunately, there is no XML parser in Boost as of the time of this writing. The library therefore contains the fast and tiny RapidXML parser (currently in version 1.13) to provide XML parsing support. RapidXML does not fully support the XML standard; it is not capable of parsing DTDs and therefore cannot do full entity substitution.

Please also refer to the XML boost tutorial.

As the OP wants a "simple way to use boost to read and write xml files", I provide below a very basic example:

<main>
    <owner>Matt</owner>
    <cats>
        <cat>Scarface Max</cat>
        <cat>Moose</cat>
        <cat>Snowball</cat>
        <cat>Powerball</cat>
        <cat>Miss Pudge</cat>
        <cat>Needlenose</cat>
        <cat>Sweety Pie</cat>
        <cat>Peacey</cat>
        <cat>Funnyface</cat>
    </cats>
</main>

(cat names are from Matt Mahoney's homepage)

The corresponding structure in C++:

struct Catowner
{
    std::string           owner;
    std::set<std::string> cats;
};

read_xml() usage:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

Catowner load(const std::string &file)
{
    boost::property_tree::ptree pt;
    read_xml(file, pt);

    Catowner co;

    co.owner = pt.get<std::string>("main.owner");

    BOOST_FOREACH(
       boost::property_tree::ptree::value_type &v,
       pt.get_child("main.cats"))
       co.cats.insert(v.second.data());

    return co;
}

write_xml() usage:

void save(const Catowner &co, const std::string &file)
{
   boost::property_tree::ptree pt;

   pt.put("main.owner", co.owner);

   BOOST_FOREACH(
      const std::string &name, co.cats)
      pt.add("main.cats.cat", name);

   write_xml(file, pt);
}
+40

Well there is no specific library in boost for XML parsing, but there are lots of alternatives, here are a couple: libxml, Xerces, Expat

Of course you could use some of the other libraries in boost to aid you in making your own library, but that will probably be quite an undertaking.

And here is a whole article on the subject by IBM.

+40

Boost does not provide an XML parser atm.

Poco XML (part of the Poco C++ libs) is good and simple.

我不能評論Poco C ++庫的質量,但在風格上它與Boost非常不同。對於想要與其他Boost組件和STL良好互操作的人來說,它可能不是一個很好的匹配。我不是指命名約定(雖然​​他們可能會感激); 而是大量使用繼承,虛函數以及字符類型缺少模板。這些設計決定可能會或可能不會更好; 但它們肯定與Boost和STL完全不同。 - 理查德史密斯2016年3月25日16:35

+40

It would appear that boost serialization can read from and write-to archives in XML, if that's sufficient for your purposes.

Easier XML with Boost

有趣的是,我正在搜索XML和Boost之後發布這個確切的鏈接。 - 格雷厄姆。於2010年8月13日13:36發表

+30

Definatelly use TinyXML *thumbs up*

+20

Take a look at Arabica

+20

If you are looking for DOM functionality only, there are some suggestions already in this thread. I personally would probably not bother with a library lacking XPath support, and in C++, would use Qt. There's also TinyXPath, and Arabica claims to have XPath support, but I cannot say anything at all about those.

感謝您的答复。但我的問題是如何手動使用註釋生成給定的XML。我如何定義我的實體類fileds? - 詹姆斯2011年4月1日15:09

看看我上面的新解決方案,真的希望這會有所幫助 - 吉姆4月11日15:38

所以。描述代碼在哪裡? - 12月9日在9:14 deys

+10

From my experiences lurking on the Boost mailing list, it appears that every time XML comes up as a subject, it is diverted into a discussion about Unicode. However, since there is a potential Unicode library looming right now, I don't think it will take too long for an XML library to appear there.

In the meantime, I too have been using TinyXML.

Interesting link about RapidXML. I'll take a look at that.

+10

A warning. I love RapidXML, but it has a very nasty bug when parsing UTF16. Some valid values cause it to crash.

I would love to recommend pugixml - but it lacks namespace support, which I know is going to cause me problems.

嗨,我已經嘗試過pugixml了,那個庫中最大的問題(對我來說當然)是缺少一些工具來將模式轉換為C ++,所以我回到“重”xerces :)並使用這個codesynthesis.com/projects/xsd這是有趣的 - Nuno 2011年1月5日9:56

+10

There is a GSoC proposed work to improve the existing proposal of Boost.XML : https://github.com/stefanseefeld/boost.xml but as Andrzej proposed Boost.PropertyTree is nice for this task. Depending naturally of the xml size and the validation support needed.

There is also a library which was recently proposed on the Boost Mailing List : http://www.codesynthesis.com/projects/libstudxml/doc/intro.xhtml

太棒了。最後,我可以開始使用API​​ :)。 - C4d 2016年7月3日23:20

而不是SelectSingleNode(“// field1”)。值應該是SelectSingleNode(“// field1”)。InnerText或SelectSingleNode(“// field1”)。InnerXml,因為Value將為null,因為它不是屬性,但值是在標籤之間。 - Mathias Conradt 2016年7月21日14:17

要添加到@MathiasConradt,它應該是SelectSingleNode(“field1”)。InnerText如果你不想總是讀取myDataz / listS / sog第一次出現的field1。 - Matthieu M. 18年12月12日10:27

0

What about boost.spirit?

Here, they show a "Mini XML" parser

0
<?xml version="1.0"?>
<Settings>
  <GroupA>
      <One>4</One>
      <Two>7</Two>
      <Three>9</Three> 
  </GroupA>
  <GroupA>
      <One>454</One>
      <Two>47</Two>
      <Three>29</Three> 
  </GroupA>
  <GroupB>
      <A>String A</A>
      <B>String B</B>  
  </GroupB>  
</Settings>

There is an easy way to read XML with BOOST. This example is with std::wstring based:

#include <string> 
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/foreach.hpp>

bool CMyClass::ReadXML(std::wstring &full_path)
{
    using boost::property_tree::wptree;

    // Populate tree structure pt:
    wptree pt;
    std::wstringstream ss; ss << load_text_file(full_path); // See below for ref.
    read_xml(ss, pt);

    // Traverse pt:
    BOOST_FOREACH(wptree::value_type const& v, pt.get_child(L"Settings"))
    {
        if (v.first == L"GroupA")
        {
            unsigned int n1 = v.second.get<unsigned int>(L"One");
            unsigned int n2 = v.second.get<unsigned int>(L"Two");
            unsigned int n3= v.second.get<unsigned int>(L"Three");
        }
        else if (v.first == L"GroupB")
        {
            std::wstring wstrA = v.second.get<std::wstring>(L"A");
            std::wstring wstrB = v.second.get<std::wstring>(L"B");
        }
    };
}

To read attributes is just a little bit more complicated.

-

Just for the reference:

std::wstring load_text_file(std::wstring &full_path)
{
    std::wifstream wif(full_path);

    wif.seekg(0, std::ios::end);
    buffer.resize(wif.tellg());
    wif.seekg(0);
    wif.read(buffer.data(), buffer.size());

    return buffer;
}
0
votes
answers
23 views
+10

如何隱藏自定義類中的迭代器和容器實現(不提升)

0

在最後一天左右,我一直在爲此而煩惱。我想弄清楚如何在隱藏類正在使用的容器類型時從類中返回迭代器。一個例子是我有一個類畫布,它擁有相同界面的小部件,並且它們被私人存儲在一個std :: vector中。所以....如何隱藏自定義類中的迭代器和容器實現(不提升)

簡化代碼

class Canvas 
{ 
public: 
    WidgetIterator begin(); 
    WidgetIterator end(); 
private: 
    class Impl; 
    std::unique_ptr<Impl> mImpl; 
}; 

class Canvas::Impl 
{ 
public: 
    std::vector<widget> mWidget; 
    //how to return mWidget.begin(), mWidget.end() up as widget iterator?? 
} 

usage: 
int main() 
{ 
    Canvas canvas(); 
    ...Fill canvas with widgets... 
    //iterate over widgets 
    for(auto& a_widget : canvas) 
    { 
     //do something with/to a_widget. User does not know or care 
     //that underlying iterator is std::vector<widget>::iterator 
    } 
    ...Do more stuff.... 
    return 0; 
} 

基本上,我想以某種別名mWidget.begin()和mWidget.end()向上穿過帆布::開始()和Canvas: :結束()。用戶知道迭代器是一個小部件,他們只是不需要知道迭代器是std :: vector :: iterator。我試圖使用PIMPL來隱藏我的實現,並保存關於事物如何存儲在類中的信息。

我似乎無法找到正確的「公式」。我已經看過類型擦除,並試圖通過接口返回函數指針,但我似乎無法想出一種方法來保持std :: vector :: iterator不在標題中,以及我迄今爲止所看到的所有內容看起來這似乎不符合我想要做的。有人能指引我朝着正確的方向嗎?閱讀材料?有沒有我失蹤的概念?噢 - 我已經看到了一些有用的例子,我無法弄清楚如何在我的情況下工作。我想避免這種情況,因爲我試圖減少外部依賴。

非常感謝您提前!

+0

你不能只是*文件*,你的WidgetIterator是一個*未指定的*隨機訪問迭代器(或任何你想要的迭代器類)?例如,標準庫不會對其迭代器類型施加特殊的限制,除了迭代器概念所強加的類型(例如,vector <> :: iterator可能只是一個指針)... –

+1

實現您自己的迭代器。它可以在內部使用std :: vector迭代器,或者不使用。迭代器必須實現很少的「功能」才能使用。 –

+0

所以迭代是一個非常密集的過程,涉及與迭代器的大量交互。你認爲重擊性能很好嗎? – Yakk

沙发
0
0

鍵入擦除迭代器的最簡單方法是編寫輸入迭代器生成器。

這足以for(:)循環,但並非所有其他的算法,並可以很容易地包裝任何隨機存取容器:

template<class T> 
struct gen_iterator_t { 
    std::function<T(std::size_t)> f; 
    std::size_t n = 0; 
    gen_iterator& operator++() { ++n; return *this; } 
    gen_iterator operator++(int) { auto r = *this; ++*this; return r; } 
    T operator*() { return f(n); } 
    gen_iterator_t(gen_iterator_t const&)=default; 
    gen_iterator_t(gen_iterator_t &&)=default; 
    gen_iterator_t& operator=(gen_iterator_t const&)=default; 
    gen_iterator_t& operator=(gen_iterator_t &&)=default; 
    gen_iterator_t()=default; 

    explicit operator bool() const { return static_cast<bool>(f); } 

    gen_iterator_t(std::function<T(std::size_t)> fin, std::size_t i): 
    f(fin), n(i) 
    {} 

    friend bool operator==(gen_iterator_t const& lhs, gen_iterator_t const& rhs) { 
    if (!lhs && !rhs) return true; 
    if (!lhs || !rhs) return false; 
    return lhs.n == rhs.n; 
    } 
    friend bool operator==(gen_iterator_t const& lhs, gen_iterator_t const& rhs) { 
    return !(lhs==rhs); 
    } 
}; 

然後我們寫range

template<class It> 
struct range_t { 
    It b, e; 
    It begin() const { return b; } 
    It end() const { return e; } 
}; 
template<class It> 
range_t<It> range(It s, It f) { return {s,f}; } 

,併產生範圍:

template<class F> 
range_t< gen_iterator_t< std::result_of_t<F&(std::size_t)> > > 
generate_range(F f, std::size_t start, std::size_t finish) { 
    return { {f, start}, {f, finish} }; 
} 

現在你的班級公開

class Canvas { 
public: 
    range_t< gen_iterator_t< widget& > > get_widgets(); 
}; 

其被實現爲

range_t< gen_iterator_t< widget& > > Canvas::get_widgets() { 
    return generate_range(
    [this](std::size_t n)->widget& { return mImpl->mWidget[n]; }, 
    0, mImpl->mWidget.size() 
); 
} 

和小露出。

如果你想更進一步,並能夠包裝非隨機訪問容器,這是更多的工作。

+0

感謝您提供非常詳細的答案。它給了我這個概念,並指出了我想要走的方向。非常感激! – tenspd137

0
votes
answers
60 views
+10

在C++中生成六位數字

-2

我有問題,應該生成六位數字的函數。這似乎是程序生成的數字,但他們總是以1 Six digit numbers在C++中生成六位數字

開始和多數民衆,使問題的一部分:

void generateNumbers(int &len, int arr[]) { 
    srand(time(0)); 

    cout << "How many numbers to generate: "; 
    cin >> len; 

    if (len <= 0 || len > 100) { 
     cout << "
 Chose number between 1 - 100
"; 
     generateNumbers(len, arr); 
    } else { 
     cout << "

The numbers: 
"; 

     for (int i = 0; i < len; i++) { 
      arr[i] = (rand() % 999999) + 100000; 
      cout << endl << arr[i]; 

     } 
    } 
} 

我pobably知道蘭特()%999999 + 100000是錯誤的但我嘗試了不同的方式,並沒有一個工作。提前致謝!

+1

你只需要因'蘭特()%90萬+ 100000' –

+1

爲000000一個六位數字?或者是第一個六位數字100000?在後一種情況下,您需要一個介於0和899999之間的隨機數並將偏移量添加到該數字中。 –

+0

@MartinBonner由於它包含的事實,它錯誤的是'900000' –

沙发
0
0

等式rand() % 900000 + 100000會給你正確的值,但是rand is considered harmful

相反,我建議你使用vectormt19937。既然你已抓獲你在len尋找數,你可以這樣做:

vector<int> arr(len); 

generate(begin(arr), end(arr), [g = std::mt19937{std::random_device{}()}]() mutable { return g() % 900000 + 100000; }); 

Live Example

0
votes
answers
29 views
+10

類型安全的事件系統實現

2

我爲我的遊戲寫了一個事件系統。它工作正常,但有一個很大的缺陷 - 它不是類型安全的,因此需要訂閱的回調函數手動強制接收基本事件。現在,我正在嘗試使用模板實現類型安全版本。我通常對這個話題很滿意,但顯然不是專家。類型安全的事件系統實現

首先,這裏是一些代碼演示如何我想使用的事件:

定義的衍生事件

// Derived Events 
class ClickEvent : public Event 
{ 
public: 
    float x; 
    float y; 
}; 

class RenderNodeCreatedEvent : public Event 
{ 
public: 
    unsigned long long int renderNodeId; 
}; 

創建它們並(在主程序例如用於測試目的)使用它們

// Create the on event functions 
std::function<void(const ClickEvent &)> onClickFunction = [](const ClickEvent & event) 
{ 
    std::cout << std::endl << "Mouse clicked at position: " << event.x << event.y; 
}; 

std::function<void(const RenderNodeCreatedEvent &)> onRenderNodeCreatedFunction = [](const RenderNodeCreatedEvent & event) 
{ 
    std::cout << std::endl << "Render node created with id: " << event.renderNodeId; 
}; 

// Create the events 
ClickEvent clickEvent; 
clickEvent.x = 300.f; 
clickEvent.y = 255.5f; 

RenderNodeCreatedEvent renderNodeCreatedEvent; 
renderNodeCreatedEvent.renderNodeId = 26234628374324; 

// Create the event manager and subscribe the event functions 
EventManager eventManager; 
eventManager.Subscribe(onClickFunction); 
eventManager.Subscribe(onRenderNodeCreatedFunction); 

// Raise the events 
eventManager.Raise(clickEvent); 
eventManager.Raise(renderNodeCreatedEvent); 

這是我試圖產生std::size_t類型的唯一ID爲每個派生事件類:

class BaseEvent 
{ 
public: 
    typedef std::size_t ID; 

    BaseEvent() = default; 
    virtual ~BaseEvent() = default; 

protected: 
    static ID GetNextID() 
    { 
     static ID id = 0; 
     return id++; 
    } 
}; 

class Event : public BaseEvent 
{ 
public: 
    Event() = default; 
    virtual ~Event() = default; 

    // Sets a unique id for the event the first time this function is called 
    ID GetID() 
    { 
     static ID id = BaseEvent::GetNextID(); 
     return id; 
    } 
}; 

最後,這是我的(可怕的)嘗試在事件管理器,可以提供上述功能。我非常努力地管理正確的投射和/或存儲不同類型的回調函數。回調包裝器不起作用 - 它只是一個基本的想法,我必須解決這個問題,所以我把它包含在帖子中。

class EventManager 
{ 
public: 
    // Define the template callback type 
    template <class DerivedEvent> 
    using TCallback = std::function<void(const DerivedEvent &)>; 

public: 
    EventManager() = default; 
    ~EventManager() = default; 

    template<class DerivedEvent> 
    void Subscribe(TCallback<DerivedEvent> callback) 
    { 
     // Get the index of the callback list this callback will be added to 
     Event::ID id = DerivedEvent::GetID(); 

     // This won't work sinve TCallback is a different type than TCallback<Event> 
     callbackListList[id].push_back(callback); 
    } 

    template <class DerivedEvent> 
    void Raise(DerivedEvent event) 
    { 
     // Get the type of the event and therefore the index in the callbackListList 
     Event::ID = DerivedEvent::GetID(); 

     /// How to cast the events back 
     // Get the respective list of callback functions 
     std::vector<TCallback<DerivedEvent>> /*&*/ callbackList; 

     // Create a callback wrapper of with the type 'derived event' ????? 
     CallbackWrapper<DerivedEvent> callbackWrapper(/*derived callback*/); 
     // Call the callback wrapper using the base event ????? 
    } 

    template <typename DerivedEvent> 
    class CallbackWrapper 
    { 
    public: 
     CallbackWrapper(TCallback<DerivedEvent> callback) : callback(callback) {} 

     void operator() (const Event & event) 
     { 
      callback(static_cast<const Event<DerivedEvent> &>(event).event); 
     } 

    private: 
     TCallback<DerivedEvent> callback; 
    }; 

private: 
    std::vector<std::vector<TCallback<Event>>> callbackListList; 
}; 

我知道這是很多代碼,但我覺得這是展示我所談論的最簡單的方法。

感謝您的幫助,阿德里安

編輯: 事件類都必須聲明爲模板,以獲得唯一ID派生類型。現在

template <class DerivedEvent> 
class Event : public BaseEvent 

從事件繼承時:

class ClickEvent : public Event<ClickEvent> 
class RenderNodeCreatedEvent : public Event<RenderNodeCreatedEvent> 

最後,eventmanager進行只能存儲類型的回調的矢量的矢量BaseEvent

private: 
    std::vector<std::vector<TCallback<BaseEvent>>> callbackListList; 
+0

也許相關:https://stackoverflow.com/questions/47337029/handling-function-pointer-with-covariant-types-uniformly-how-to-call-callbacks – geza

+0

很顯然,你不能使用類型** BaseEvent **的回調向量。將對象存儲到基礎對象類型中時,會發生切片,並且會丟失派生對象及其數據的類型。順便說一句,通過回調類型來管理經理可能更容易。也就是說,'EventManager'可能應該是一個管理特定回調類型的模板。這樣,就很容易實現類型安全。 – Phil1970

+0

@ Phil1970是的,我將不得不在列表中存儲指針。關於使事件管理器成爲一個模板的觀點:由於我想要的是單一事件系統(如果需要的話,消息系統),所有系統都可以用來通信。 –

沙发
0
0

長一些研究之後,我發現這篇文章基本上解決了ECS事件/信使實現問題:

https://codereview.stackexchange.com/questions/79211/ecs-event-messaging-implementation

13
votes
answers
23 views
+10

Detecting endianness programmatically in a C++ program

Is there a programmatic way to detect whether or not you are on a big-endian or little-endian architecture? I need to be able to write code that will execute on an Intel or PPC system and use exactly the same code (i.e. no conditional compilation).

沙发
+30

untested, but in my mind, this should work? cause it'll be 0x01 on little endian, and 0x00 on big endian?

bool runtimeIsLittleEndian(void)
{
 volatile uint16_t i=1;
 return  ((uint8_t*)&i)[0]==0x01;//0x01=little, 0x00=big
}
板凳
+30

Declare:

My initial post is incorrectly declared as "compile time". It's not, it's even impossible in current C++ standard. The constexpr does NOT means the function always do compile-time computation. Thanks Richard Hodges for correction.

compile time, non-macro, C++11 constexpr solution:

union {
  uint16_t s;
  unsigned char c[2];
} constexpr static  d {1};

constexpr bool is_little_endian() {
  return d.c[0] == 1;
}

有沒有特別的原因你使用unsigned char而不是uint8_t? - 凱文2014年11月16日20:46

0運行時開銷...我喜歡它! - hanshenrik 2015年9月11日在1:05

我猜,這會檢測構建機器的endiannes,而不是目標? - hutorny 2015年10月23日12:07

在C ++中不是這個UB嗎? - rr- 2016年2月29日21:44

這在constexpr上下文中是不合法的。您無法訪問尚未直接初始化的聯合成員。沒有預處理器魔法,沒有辦法在編譯時合法地檢測字節順序。 - 理查德霍奇斯於2016年4月15日0:24

地板
+20

You can also do this via the preprocessor using something like boost header file which can be found boost endian

4楼
+20

If you don't want conditional compilation you can just write endian independent code. Here is an example (taken from Rob Pike):

Reading an integer stored in little-endian on disk, in an endian independent manner:

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

The same code, trying to take into account the machine endianness:

i = *((int*)data);
#ifdef BIG_ENDIAN
/* swap the bytes */
i = ((i&0xFF)<<24) | (((i>>8)&0xFF)<<16) | (((i>>16)&0xFF)<<8) | (((i>>24)&0xFF)<<0);
#endif
5楼
+10
int i=1;
char *c=(char*)&i;
bool littleendian=c;
6楼
+10

How about this?

#include <cstdio>

int main()
{
    unsigned int n = 1;
    char *p = 0;

    p = (char*)&n;
    if (*p == 1)
        std::printf("Little Endian
");
    else 
        if (*(p + sizeof(int) - 1) == 1)
            std::printf("Big Endian
");
        else
            std::printf("What the crap?
");
    return 0;
}
7楼
+10

Unless the endian header is GCC-only, it provides macros you can use.

#include "endian.h"
...
if (__BYTE_ORDER == __LITTLE_ENDIAN) { ... }
else if (__BYTE_ORDER == __BIG_ENDIAN) { ... }
else { throw std::runtime_error("Sorry, this version does not support PDP Endian!");
...

這些__BYTE_ORDER __,__ ORDERLE_ENDIAN__和__ORDER_BIG_ENDIAN__不是嗎? - Xeverous 3月25日'18在21:38

8楼
0

See Endianness - C-Level Code illustration.

// assuming target architecture is 32-bit = 4-Bytes
enum ENDIANESS{ LITTLEENDIAN , BIGENDIAN , UNHANDLE };


ENDIANESS CheckArchEndianalityV1( void )
{
    int Endian = 0x00000001; // assuming target architecture is 32-bit    

    // as Endian = 0x00000001 so MSB (Most Significant Byte) = 0x00 and LSB (Least     Significant Byte) = 0x01
    // casting down to a single byte value LSB discarding higher bytes    

    return (*(char *) &Endian == 0x01) ? LITTLEENDIAN : BIGENDIAN;
} 
9楼
0

Here's another C version. It defines a macro called wicked_cast() for inline type punning via C99 union literals and the non-standard __typeof__ operator.

#include <limits.h>

#if UCHAR_MAX == UINT_MAX
#error endianness irrelevant as sizeof(int) == 1
#endif

#define wicked_cast(TYPE, VALUE) 
    (((union { __typeof__(VALUE) src; TYPE dest; }){ .src = VALUE }).dest)

_Bool is_little_endian(void)
{
    return wicked_cast(unsigned char, 1u);
}

If integers are single-byte values, endianness makes no sense and a compile-time error will be generated.

10楼
0

The way C compilers (at least everyone I know of) work the endianness has to be decided at compile time. Even for biendian processors (like ARM och MIPS) you have to choose endianness at compile time. Further more the endianness is defined in all common file formats for executables (such as ELF). Although it is possible to craft a binary blob of biandian code (for some ARM server exploit maybe?) it probably has to be done in assembly.

11楼
0

while there is no quick and standard way to determine it, this will output it:

#include <stdio.h> 
int main()  
{ 
   unsigned int i = 1; 
   char *c = (char*)&i; 
   if (*c)     
       printf("Little endian"); 
   else
       printf("Big endian"); 
   getchar(); 
   return 0; 
} 
12楼
0

Do not use a union!

C++ does not permit type punning via unions!
Reading from a union field that was not the last field written to is undefined behaviour!
Many compilers support doing so as an extensions, but the language makes no guarantee.

See this answer for more details:

https://stackoverflow.com/a/11996970


There are only two valid answers that are guaranteed to be portable.

The first answer, if you have access to a system that supports C++20,
is to use std::endian from the <type_traits> header.

(At the time of writing, C++20 has not yet been released, but unless something happens to affect std::endian's inclusion, this shall be the preferred way to test the endianness at compile time from C++20 onwards.)

C++20 Onwards

constexpr bool is_little_endian = (std::endian::native == std::endian::little);

Prior to C++20, the only valid answer is to store an integer and then inspect its first byte through type punning.
Unlike the use of unions, this is expressly allowed by C++'s type system.

It's also important to remember that for optimum portability static_cast should be used,
because reinterpret_cast is implementation defined.

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined: ... a char or unsigned char type.

C++11 Onwards

enum class endianness
{
    little = 0,
    big = 1,
};

inline endianness get_system_endianness()
{
    const int value { 0x01 };
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01) ? endianness::little : endianness::big;
}

C++11 Onwards (without enum)

inline bool is_system_little_endian()
{
    const int value { 0x01 };
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01);
}

C++98/C++03

inline bool is_system_little_endian()
{
    const int value = 0x01;
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01);
}
13楼
-10

I was going through the textbook:Computer System: a programmer's perspective, and there is a problem to determine which endian is this by C program.

I used the feature of the pointer to do that as following:

#include <stdio.h>

int main(void){
    int i=1;
    unsigned char* ii = &i;

    printf("This computer is %s endian.
", ((ii[0]==1) ? "little" : "big"));
    return 0;
}

As the int takes up 4 bytes, and char takes up only 1 bytes. We could use a char pointer to point to the int with value 1. Thus if the computer is little endian, the char that char pointer points to is with value 1, otherwise, its value should be 0.

這將通過使用int32t得到改善。 - shuttle87 2014年11月11日16:53

^如果你想挑剔,這裡最好的是int16_fast_t。和@Ageimedes520的當前代碼將不適用於其中int本身就是int8;)(儘管可能首先違反c標準) - hanshenrik 2015年9月11日在1:11

14楼
-10

As pointed out by Coriiander, most (if not all) of those codes here will be optimized away at compilation time, so the generated binaries won't check "endianness" at run time.

It has been observed that a given executable shouldn't run in two different byte orders, but I have no idea if that is always the case, and it seems like a hack to me checking at compilation time. So I coded this function:

#include <stdint.h>

int* _BE = 0;

int is_big_endian() {
    if (_BE == 0) {
        uint16_t* teste = (uint16_t*)malloc(4);
        *teste = (*teste & 0x01FE) | 0x0100;
        uint8_t teste2 = ((uint8_t*) teste)[0];
        free(teste);
        _BE = (int*)malloc(sizeof(int));
        *_BE = (0x01 == teste2);
    }
    return *_BE;
}

MinGW wasn't able to optimize this code, even though it does optimize the other codes here away. I believe that is because I leave the "random" value that was alocated on the smaller byte memory as it was (at least 7 of its bits), so the compiler can't know what that random value is and it doesn't optimize the function away.

I've also coded the function so that the check is only performed once, and the return value is stored for next tests.

為什麼要分配4個字節來處理2字節值?為什麼用0x7FE掩蓋不確定的值?為什麼要使用malloc()?這很浪費。_BE是一個(雖然很小)內存洩漏和等待發生的競爭條件,動態緩存結果的好處並不值得。我會做更像這樣的事情:static const uint16_t teste = 1; int is_little_endian(){return(0x01 ==((uint8_t *)&teste)[0]); } int is_big_endian(){return(0x01 ==((uint8_t *)&teste)[1]); 簡單有效,在運行時執行的工作少得多。 - Remy Lebeau,18年5月3日0:08

這太糟糕了...... - YSC於18年11月27日14:32

@RemyLebeau,我的答案的重點是產生一個未經編譯器優化的代碼。當然,你的代碼更簡單,但啟用優化後,它將在編譯後成為一個常量布爾值。正如我在回答中所說,我實際上並不知道是否有某種方式來編譯C代碼的方式是在兩個字節順序上運行相同的可執行文件,我也很想知道我是否可以在運行時進行檢查儘管優化正在進行中。 - Tex Killer 5月14日3:22

@TexKiller然後為什麼不簡單地禁用代碼的優化?使用volatile或#pragma等 - Remy Lebeau 5月14日4:23

@RemyLebeau,我當時並不知道那些關鍵字,我只是把它作為一個小挑戰,以防止我知道的編譯器優化。 - Tex Killer 5月29日13:27

0
votes
answers
27 views
+10

開放解決方案/項目與Visual Studio 2015時沒有SLN文件

0

我剛剛在github上下載了開放源代碼https://github.com/alextrevisan/SFML-LiquidFun-Water 而且,我打開visual studio 2015並試圖打開它,但沒有像.sln文件這樣的東西。 。 在這種情況下,我該如何打開該項目?以及我應該在哪裏找到所有文件。 enter image description here開放解決方案/項目與Visual Studio 2015時沒有SLN文件

+0

打開'由[碼塊] .cpb'文件(http://www.codeblocks.org/)。 – Arash

+0

想知道如何解決與視覺如果沒關係.. –

+0

哦,所以你的意思是源代碼是由CodeBlocks而不是視覺API? –

沙发
0
0

嘗試文件 - >新建 - >從現有代碼項目。然後選擇源文件夾並編譯。

您可能不得不在嚮導的幾個選項(如是否是一個控制檯應用程序或者需要一些依賴),這取決於原始代碼::塊項目已經建立。但如果它是符合標準的C++,它應該編譯並運行,而不需要任何花哨的編譯器設置。

0
votes
answers
36 views
+10

When can I use a forward declaration?

I am looking for the definition of when I am allowed to do forward declaration of a class in another class's header file:

Am I allowed to do it for a base class, for a class held as a member, for a class passed to member function by reference, etc. ?

0
votes
answers
26 views
+10

SFINAE模板成員超載

2

我想專精getVector成員函數,我正在嘗試使用SFINAE。但它只有在Dim爲3或更大時纔有效。SFINAE模板成員超載

template <size_t Dim> 
class Mat 
{ 
    ... 
    template <size_t VDim, typename enable_if<(Dim > 1 && VDim == 0)>::type* = nullptr> 
     void getVectorBegin(const array<size_t, Dim - 1>& indexAfter) const; 

    template <size_t VDim, typename enable_if<(Dim > 2 && 0 < VDim && VDim < Dim-1)>::type* = nullptr> 
     void getVectorBegin(const array<size_t, VDim>& indexBefore, const array<size_t, Dim - VDim - 1>& indexAfter) const; 

    template <size_t VDim, typename enable_if<(Dim > 1 && VDim == Dim-1)>::type* = nullptr> 
     void getVectorBegin(const array<size_t, Dim - 1>& indexBefore) const; 
}; 

Mat<3> m; 
Mat<2> m; // error C2039: 'type': is not a member of 'std::enable_if<false,_Ty>' 
+0

您是否嘗試將「Dim> x」檢查作爲最後的&&術語?我不確定編譯器是否正確,或者它只是實現定義的,但它可能會縮短enable_if條件,並認爲它的值不依賴於VDim,因此在成員聲明實例化期間發生編譯器錯誤(即,在Mat <2>瞬間點) –

+0

有些東西你沒有向我們展示。如果不使用模板類的成員函數,則不會實例化。你能告訴我們呼叫網站嗎? – papagaga

+4

@papagaga這不完全正確,成員函數聲明(但不是它們的定義)在類模板時被實例化。因此,如果聲明在類模板參數中包含一個僅依賴於值的表達式,並且表達式結果不正確,那麼即使該函數未被「使用」也會產生錯誤... –

0
votes
answers
35 views
+10

Qt 5.9.2:沒有有效的工具包在Windows 7上找到

0

我已經安裝Qt5.9.2 64bit Windows 7操作系統從這個link,evrything是好的,直到我想創建一個新的GUI應用程序項目,它說:「找不到有效的工具包」,我能夠添加和管理C++編譯器,但是我找不到用於管理Qt版本的「qmake」文件。任何解決方案Qt 5.9.2:沒有有效的工具包在Windows 7上找到

+0

檢查你的Qt安裝目錄像C: Qt Qt5.9.1 5.9.1 msvc2015 bin在這裏你可以找到qmake。只需補充一點,它將起作用。 – SourabhKus

+0

感謝您的回答,但Qt基礎文件夾中的任何位置都沒有「mvsc」文件夾。 –

+0

只需進入C: Qt並在文件資源管理器中搜索qmake,您將獲得路徑。我寫了我的qmake路徑僅供參考。 – SourabhKus

沙发
0
1

MINGW

看看這裏我使用MinGW的編譯器,庫。如果你有VisualStudio,你也可以選擇相應的庫。

+0

我在你的答案上提到過上面提到的,現在它說該警告「qmake」不適合我的Qt版本,我檢查了Qcreator版本,並且我發現它基於32位系統,我應該使用msvc2015 32位嗎? –

+1

首先檢查你的編譯器安裝相同的Qt庫如我的Visual Studio 2017 x64安裝在我的電腦上,所以我安裝了msvc2017-64位Qt庫。如果你沒有任何編譯器,你可以安裝mingw – SourabhKus

0
votes
answers
47 views
+10

指定具有絕對路徑的庫的GCC行爲是什麼

0

GCC(鏈接)是否在用絕對路徑指定時找不到庫。請注意,我想要這樣做的原因是我有一個構建系統,可以通過絕對路徑解決所有庫問題,因此它可以保留一組有序的唯一條目。指定具有絕對路徑的庫的GCC行爲是什麼

g++ (...) -l/path/to/library.so 

我看到一個bug報告,其中有些人認爲這是一個錯誤,和其他人認爲它曾經工作過的事實是一個錯誤,這是固定的。

有一些討論,一個曾與一個先於道「:」

反正沒能正常工作。

因此,爲了在構建系統中進行測試,我將代碼放在絕對庫路徑中,如果它的「前綴」與指定給GCC的任何庫路徑匹配並截斷絕對庫路徑。

g++ (...) -L/path/to -llibrary.so 

這工作。
我也試過這個。

g++ (...) -L/path/to -l/path/to/library.so 

它工作。 9(雖然調查..看起來像這是在構建腳本中的錯誤)

似乎如果任何指定爲GCC的搜索路徑是指定一個絕對路徑的庫的「前綴」,它會找到該庫。我還假定它需要在提供的庫路徑的有序列表中的第一個命中。

所以我的問題。

  • 這種支持行爲?
  • 這是更好的截斷構建腳本中的絕對庫路徑或通過絕對路徑。

我啓事帶來了一些相關的問題在這裏:

How to link using GCC without -l nor hardcoding path for a library that does not follow the libNAME.so naming convention?

這表明「非搜索」完整路徑是「燒」到可執行從而覆蓋所有運行時庫路徑當它是執行?它是否正確 ?如果是這樣,則意味着在命令行上指定具有完整路徑的庫是不合適的。部署時,構建的應用程序和關聯的庫將安裝在標準的可搜索位置。

沙发
0
1

我想在這種情況下說的不使用-l,只是通過完整的庫路徑作爲命令的一部分: GCC(其他選項)/path/to/library.so

+0

這意味着它將通過查看後綴來確定它是一個庫嗎? – peterk

+0

@peterk:不,Unix通常不支持文件。它將通過查看文件的結構來確定它是一個庫。 –

+0

@MartinBonner GCC不會自動查找相應的存根'.a'文件嗎? – user0042

板凳
0
0

注:此是與gcc(Raspbian 4.9.2-10)4.9.2我正在爲它建立一個庫集。

好 - 多敲打它,並測試不同的情況下

使用完整路徑作爲參數傳遞給GCC在硬編碼的絕對路徑顯然燃燒到用於在運行時解決它是圖書館。這是不希望的,因爲應用程序旨在與可搜索的共享庫一起部署,最終可能會在不同的地方出現。

-llibmyLib.so does not work with a search path. 
-lmyLib   does work with a search path 
    (with lib prefix and suffix removed - apparently 
     it tries all available suffi and prepends "lib" for it's 
     search by default) 

-

-l:libmyLib.so DOES work with a search path, 
       as ':' specifies the file name is not to be altered. 

-l:debug/libmyLib.so DOES work (a subdir under the search path) 
-l:release/libmyLib.so DOES work (a subdir under the search path) 

有了這個信息 - (顯然)知道它做什麼,現在我可以繼續前進!