Функция, возвращающая разные значения в разных конфигурациях

#c #g

#c #g

Вопрос:

вот фрагмент моего кода:

 int fastcmp(const void* ptr1, const void* ptr2, size_t size)
{
    if (ptr1 == ptr2) return 0;
    if (!ptr1 || !ptr2) return -1;

    size_t remain = size;
    if (size >= 8)
    {
        remain = size % 8;
        size_t work = size / 8   1;
        auto p1 = (const uint64_t*) ((const uint8_t*)ptr1   remain);
        auto p2 = (const uint64_t*) ((const uint8_t*)ptr2   remain);
        while(--work > 0)
            if(p1[work] != p2[work]) return -1;
    }

    auto p1 = (const uint8_t*) ptr1;
    auto p2 = (const uint8_t*) ptr2;
    while(remain-- > 0) 
        if (p1[remain] != p2[remain]) return -1;
    
    return 0;
}

int main(int argc, char* argv[])
{
    if (argc == 3)
    {
        size_t len1 = strlen(argv[1]);
        size_t len2 = strlen(argv[2]);
        if (len1 == len2)
        {
            std::cout << "fastcmp returns:" << fastcmp(argv[1], argv[2], len1) << std::endl;
            std::cout << "memcmp returns:" << memcmp(argv[1], argv[2], len1) << std::endl;
        }
    }
    return 0;
}
 

итак, я использую coderunner в vscode и g из mingw. я настроил launch.json с обоими аргументами точно так же. запустите отладку, и функция вернет 0. после этого я скомпилировал ее с помощью g и попытался запустить с помощью терминала с теми же аргументами, которые я написал в launch.json. но функция возвращает значение -1. кто-нибудь может объяснить, почему? спасибо, это сбивает меня с толку.

fastcmp возвращает -1, если strlen > 8

g -std=c 11 foo.cpp -о фу

Комментарии:

1. Ваше предположение о выравнивании кажется странным…

2. вы не смотрите на правильные индексы, смотрите Мой ответ

3. Код педантично UB, с нарушением правил строгого сглаживания и арифметическим указателем не на массив uint64_t

4. @Jarod42 да, тот факт, что поведение зависит от компилятора, является показателем неопределенного поведения

Ответ №1:

В fastcmp просто замените

 size_t work = size / 8   1;
 

Автор:

 size_t work = size / 8;
 

и

 while(--work > 0) {
 

Автор:

 while(work-- != 0) {
 

иначе вы смотрите на индексы n..1, а не n..0, поэтому вы не обнаруживаете разницы в оставшихся 0..7 символах

( примечание size_t не подписано)

обратите внимание, что вы предполагаете, что можете прочитать uint64_t с любого выравнивания, считывать со смещения 0, а не оставаться более безопасным (строки в argv[i] выровнены, чтобы быть совместимыми с любым размером числа), в любом случае, как сказано в замечании, у вас нарушение правил строгого сглаживания, и ваша разница в поведении является следствиемиз-за этого неопределенного поведения

Ответ №2:

Я не могу сразу сказать вам, почему это происходит, но есть способ выяснить. Основная проблема при определении источника проблемы заключается в том, что многие ветви возвращают -1 (я вижу 3). Я бы рекомендовал изменить это либо на другие значения, либо добавить какое-либо заявление о регистрации. Затем вы можете проверить условие, которое его вызвало. Вероятно, это связано со всеми выполняемыми вами кастингами. Если проблема заключается в приведении, рассмотрите возможность использования статических приведений и отказа от использования указателей в стиле c и перехода на современные общие указатели. Современные расширения c имеют целью сделать язык более понятным, а в некоторых случаях сделать компиляцию более детерминированной.

Комментарии:

1. в чем ваш ответ… это ответ?

2. я пробовал это, но это не работает. спасибо за ответ.