Ошибка необъяснимой связи [дубликат]

Я сделал это, потому что мне нужен был простой способ разделить строки и строки на основе c ... Надеюсь, кто-то еще сможет найти его полезным. Кроме того, он не полагается на токены, и вы можете использовать поля в качестве разделителей, что еще один ключ, который мне нужен.

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

StringSplitter.hpp:

#include <vector>
#include <iostream>
#include <string.h>

using namespace std;

class StringSplit
{
private:
    void copy_fragment(char*, char*, char*);
    void copy_fragment(char*, char*, char);
    bool match_fragment(char*, char*, int);
    int untilnextdelim(char*, char);
    int untilnextdelim(char*, char*);
    void assimilate(char*, char);
    void assimilate(char*, char*);
    bool string_contains(char*, char*);
    long calc_string_size(char*);
    void copy_string(char*, char*);

public:
    vector<char*> split_cstr(char);
    vector<char*> split_cstr(char*);
    vector<string> split_string(char);
    vector<string> split_string(char*);
    char* String;
    bool do_string;
    bool keep_empty;
    vector<char*> Container;
    vector<string> ContainerS;

    StringSplit(char * in)
    {
        String = in;
    }

    StringSplit(string in)
    {
        size_t len = calc_string_size((char*)in.c_str());
        String = new char[len + 1];
        memset(String, 0, len + 1);
        copy_string(String, (char*)in.c_str());
        do_string = true;
    }

    ~StringSplit()
    {
        for (int i = 0; i < Container.size(); i++)
        {
            if (Container[i] != NULL)
            {
                delete[] Container[i];
            }
        }
        if (do_string)
        {
            delete[] String;
        }
    }
};

StringSplitter.cpp:

#include <string.h>
#include <iostream>
#include <vector>
#include "StringSplit.hpp"

using namespace std;

void StringSplit::assimilate(char*src, char delim)
{
    int until = untilnextdelim(src, delim);
    if (until > 0)
    {
        char * temp = new char[until + 1];
        memset(temp, 0, until + 1);
        copy_fragment(temp, src, delim);
        if (keep_empty || *temp != 0)
        {
            if (!do_string)
            {
                Container.push_back(temp);
            }
            else
            {
                string x = temp;
                ContainerS.push_back(x);
            }

        }
        else
        {
            delete[] temp;
        }
    }
}

void StringSplit::assimilate(char*src, char* delim)
{
    int until = untilnextdelim(src, delim);
    if (until > 0)
    {
        char * temp = new char[until + 1];
        memset(temp, 0, until + 1);
        copy_fragment(temp, src, delim);
        if (keep_empty || *temp != 0)
        {
            if (!do_string)
            {
                Container.push_back(temp);
            }
            else
            {
                string x = temp;
                ContainerS.push_back(x);
            }
        }
        else
        {
            delete[] temp;
        }
    }
}

long StringSplit::calc_string_size(char* _in)
{
    long i = 0;
    while (*_in++)
    {
        i++;
    }
    return i;
}

bool StringSplit::string_contains(char* haystack, char* needle)
{
    size_t len = calc_string_size(needle);
    size_t lenh = calc_string_size(haystack);
    while (lenh--)
    {
        if (match_fragment(haystack + lenh, needle, len))
        {
            return true;
        }
    }
    return false;
}

bool StringSplit::match_fragment(char* _src, char* cmp, int len)
{
    while (len--)
    {
        if (*(_src + len) != *(cmp + len))
        {
            return false;
        }
    }
    return true;
}

int StringSplit::untilnextdelim(char* _in, char delim)
{
    size_t len = calc_string_size(_in);
    if (*_in == delim)
    {
        _in += 1;
        return len - 1;
    }

    int c = 0;
    while (*(_in + c) != delim && c < len)
    {
        c++;
    }

    return c;
}

int StringSplit::untilnextdelim(char* _in, char* delim)
{
    int s = calc_string_size(delim);
    int c = 1 + s;

    if (!string_contains(_in, delim))
    {
        return calc_string_size(_in);
    }
    else if (match_fragment(_in, delim, s))
    {
        _in += s;
        return calc_string_size(_in);
    }

    while (!match_fragment(_in + c, delim, s))
    {
        c++;
    }

    return c;
}

void StringSplit::copy_fragment(char* dest, char* src, char delim)
{
    if (*src == delim)
    {
        src++;
    }

    int c = 0;
    while (*(src + c) != delim && *(src + c))
    {
        *(dest + c) = *(src + c);
        c++;
    }
    *(dest + c) = 0;
}

void StringSplit::copy_string(char* dest, char* src)
{
    int i = 0;
    while (*(src + i))
    {
        *(dest + i) = *(src + i);
        i++;
    }
}

void StringSplit::copy_fragment(char* dest, char* src, char* delim)
{
    size_t len = calc_string_size(delim);
    size_t lens = calc_string_size(src);

    if (match_fragment(src, delim, len))
    {
        src += len;
        lens -= len;
    }

    int c = 0;
    while (!match_fragment(src + c, delim, len) && (c < lens))
    {
        *(dest + c) = *(src + c);
        c++;
    }
    *(dest + c) = 0;
}

vector<char*> StringSplit::split_cstr(char Delimiter)
{
    int i = 0;
    while (*String)
    {
        if (*String != Delimiter && i == 0)
        {
            assimilate(String, Delimiter);
        }
        if (*String == Delimiter)
        {
            assimilate(String, Delimiter);
        }
        i++;
        String++;
    }

    String -= i;
    delete[] String;

    return Container;
}

vector<string> StringSplit::split_string(char Delimiter)
{
    do_string = true;

    int i = 0;
    while (*String)
    {
        if (*String != Delimiter && i == 0)
        {
            assimilate(String, Delimiter);
        }
        if (*String == Delimiter)
        {
            assimilate(String, Delimiter);
        }
        i++;
        String++;
    }

    String -= i;
    delete[] String;

    return ContainerS;
}

vector<char*> StringSplit::split_cstr(char* Delimiter)
{
    int i = 0;
    size_t LenDelim = calc_string_size(Delimiter);

    while(*String)
    {
        if (!match_fragment(String, Delimiter, LenDelim) && i == 0)
        {
            assimilate(String, Delimiter);
        }
        if (match_fragment(String, Delimiter, LenDelim))
        {
            assimilate(String,Delimiter);
        }
        i++;
        String++;
    }

    String -= i;
    delete[] String;

    return Container;
}

vector<string> StringSplit::split_string(char* Delimiter)
{
    do_string = true;
    int i = 0;
    size_t LenDelim = calc_string_size(Delimiter);

    while (*String)
    {
        if (!match_fragment(String, Delimiter, LenDelim) && i == 0)
        {
            assimilate(String, Delimiter);
        }
        if (match_fragment(String, Delimiter, LenDelim))
        {
            assimilate(String, Delimiter);
        }
        i++;
        String++;
    }

    String -= i;
    delete[] String;

    return ContainerS;
}

Примеры:

int main(int argc, char*argv[])
{
    StringSplit ss = "This:CUT:is:CUT:an:CUT:example:CUT:cstring";
    vector<char*> Split = ss.split_cstr(":CUT:");

    for (int i = 0; i < Split.size(); i++)
    {
        cout << Split[i] << endl;
    }

    return 0;
}

Будет output:

Это пример cstring

int main(int argc, char*argv[])
{
    StringSplit ss = "This:is:an:example:cstring";
    vector<char*> Split = ss.split_cstr(':');

    for (int i = 0; i < Split.size(); i++)
    {
        cout << Split[i] << endl;
    }

    return 0;
}

int main(int argc, char*argv[])
{
    string mystring = "This[SPLIT]is[SPLIT]an[SPLIT]example[SPLIT]string";
    StringSplit ss = mystring;
    vector<string> Split = ss.split_string("[SPLIT]");

    for (int i = 0; i < Split.size(); i++)
    {
        cout << Split[i] << endl;
    }

    return 0;
}

int main(int argc, char*argv[])
{
    string mystring = "This|is|an|example|string";
    StringSplit ss = mystring;
    vector<string> Split = ss.split_string('|');

    for (int i = 0; i < Split.size(); i++)
    {
        cout << Split[i] << endl;
    }

    return 0;
}

Чтобы сохранить пустые записи (по умолчанию будут исключены пустые):

StringSplit ss = mystring;
ss.keep_empty = true;
vector<string> Split = ss.split_string(":DELIM:");

Целью было: чтобы сделать его похожим на метод C # Split (), где разделение строки так же просто, как:

String[] Split = 
    "Hey:cut:what's:cut:your:cut:name?".Split(new[]{":cut:"}, StringSplitOptions.None);

foreach(String X in Split)
{
    Console.Write(X);
}

Я надеюсь, что кто-то другой найдет это полезным как я.

64
задан 10 August 2012 в 01:42
поделиться

3 ответа

Так как работает алгоритм связывания, используемый GNU-компоновщиком (как минимум, когда речь идет о связывании статических библиотек). Линкером является однопроходный компоновщик, и он не пересматривает библиотеки после их просмотра.

Библиотека представляет собой коллекцию (архив) объектных файлов. Когда вы добавляете библиотеку с помощью опции -l, компоновщик не безоговорочно принимает все объектные файлы из библиотеки. Для этого нужны только те объектные файлы, которые в настоящее время необходимы , то есть файлы, которые разрешают некоторые нерешенные (ожидающие) символы. После этого компоновщик полностью забывает об этой библиотеке.

Список ожидающих символов постоянно поддерживается компоновщиком, поскольку компоновщик обрабатывает файлы входных объектов один за другим слева направо. Когда он обрабатывает каждый объектный файл, некоторые символы разрешаются и удаляются из списка, другие вновь обнаруженные неразрешенные символы добавляются в список.

Итак, если вы включили некоторую библиотеку с помощью -l, компоновщик использует эту библиотеку для разрешения как можно большего количества текущих ожидающих символов, а затем полностью забывает об этой библиотеке. Если позднее позже внезапно обнаруживает, что теперь ему нужны некоторые дополнительные объектные файлы из этой библиотеки, компоновщик не будет «возвращаться» к этой библиотеке для извлечения этих дополнительных объектных файлов. Уже слишком поздно.

По этой причине всегда полезно использовать опцию -l late в командной строке компоновщика, так что к тому времени, когда линкер достигнет этого -l он может надежно определить, какие файлы объектов ему нужны и которые ему не нужны. Размещение параметра -l в качестве самого первого параметра в компоновщике вообще не имеет никакого смысла: в самом начале список ожидающих символов пуст (или, точнее, состоит из одного символа main), что означает, что linker вообще ничего не берет из библиотеки.

В вашем случае ваш объектный файл example.o содержит ссылки на символы ud_init, ud_set_input_file и т. д. Линкером следует сначала получить этот объектный файл. Он добавит эти символы в список ожидающих символов. После этого вы можете использовать опцию -l, чтобы добавить вашу библиотеку: -ludis86. Линкер будет искать вашу библиотеку и взять все, что разрешает эти ожидающие символы.

Если вы поместите параметр -ludis86 сначала в командной строке, компоновщик будет эффективно игнорировать вашей библиотеки, так как вначале он не знает, что ему понадобятся ud_init, ud_set_input_file и т. д. Позже, при обработке example.o, он обнаружит эти символы и добавит их в список ожидающих символов. Но эти символы останутся неразрешенными до конца, так как -ludis86 уже обработан (и эффективно игнорируется).

Иногда, когда две (или более) библиотеки ссылаются друг на друга круговым способом, можно даже необходимо использовать параметр -l дважды с той же библиотекой, чтобы дать компоновщику две возможности для извлечения необходимых объектных файлов из этой библиотеки.

89
ответ дан jww 25 August 2018 в 20:59
поделиться

Я снова ударил эту же проблему a назад. Итог заключается в том, что инструменты gnu не всегда будут «искать назад» в списке библиотек для устранения недостающих символов. Легкие исправления являются следующими:

  1. Просто укажите libs и objs в порядке зависимости (как вы обнаружили выше)
  2. ИЛИ если у вас есть круговая зависимость ( где libA ссылается на функцию в libB, но libB ссылается на функцию в libA), а затем просто укажите libs в командной строке дважды. Это то, что предлагает справочная страница. Например.
    gcc foo.c -lfoo -lbar -lfoo
    
  3. Используйте параметры -( и -), чтобы указать группу архивов с такими круговыми зависимостями. Посмотрите руководство GNU-linker для --start-group и --end-group. Подробнее см. В здесь .

Когда вы используете опцию 2 или 3, вы, вероятно, вводите стоимость исполнения для связи. Если у вас не так много ссылок, это может не иметь значения.

8
ответ дан Community 25 August 2018 в 20:59
поделиться

Или используйте rescan

из стр. 41 из Руководство для библиотек и библиотек Oracle Solaris 11.1 :

Между системами могут существовать взаимозависимости, извлечение членов из одного архива должно быть разрешено путем извлечения членов из другого архива. Если эти зависимости являются циклическими, архивы должны быть повторно указаны в командной строке для удовлетворения предыдущих ссылок.

$ cc -o prog .... -lA -lB -lC -lA -lB -lC -lA 

Определение и обслуживание повторяющихся архивных спецификаций может быть утомительным.

Опция -z rescan-now делает этот процесс более простым. Опция -z rescan-now обрабатывается редактором ссылок сразу же, когда опция встречается в командной строке. Все архивы, обработанные из командной строки до этой опции, сразу же обрабатываются. Эта обработка пытается найти дополнительные элементы архива, которые разрешают ссылки на символы. Повторное сканирование этого архива продолжается до тех пор, пока не произойдет переполнение списка архивов, в котором не будут извлечены новые члены. Предыдущий пример можно упростить следующим образом.

$ cc -o prog .... -lA -lB -lC -z rescan-now 

В качестве альтернативы опции повторного сканирования и -z для повторного сканирования могут быть использованы для группировки взаимозависимых архивов вместе в группу архива. Эти группы обрабатываются редактором ссылок сразу же, когда в командной строке встречается разделительный разделитель. Архивы, найденные внутри группы, перерабатываются в попытке найти дополнительные элементы архива, которые разрешают ссылки на символы. Повторное сканирование этого архива продолжается до тех пор, пока не произойдет прохождение группы архива, в которой не будут извлекаться новые члены. Используя архивные группы, предыдущий пример можно записать следующим образом.

$ cc -o prog .... -z rescan-start -lA -lB -lC -z rescan-end
4
ответ дан trogdor 25 August 2018 в 20:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: