Различное значение указателя до и после возврата

У меня странная проблема, я выделил память с помощью malloc и вернул адрес этой вновь выделенной памяти. Но этот адрес отличается до и после возврата (внутри и снаружи функции).

Вот код (заботьтесь только о 3 последних строках):

char* InfoFile_getValue(char* projectName, char* key)
{
    char* returnValue = NULL;

    char projectInfoPath[200];
    sprintf(projectInfoPath,"projects/%s/info.txt",projectName);

    FILE* fp = fopen(projectInfoPath,"r");

    if (fp != NULL) {
        char* ptr;
        size_t len = 0;
        char* lineFromFile = NULL;
        while(getline(&lineFromFile, &len, fp)!=-1)
        {
            if (strstr(lineFromFile,key))
            {
                ptr = lineFromFile + strlen(key);
                ptr = ptr + strspn(ptr, ": ");
                returnValue = malloc(strlen(ptr)+1);
                strcpy(returnValue,ptr);
                break;
            } 
        }
        free(lineFromFile);
        fclose(fp);
    }
    
    printf("Inside size: %d\n",sizeof(returnValue));
    printf("String address inside function %p\n", returnValue);
    return returnValue;
}

И затем я вызываю эту функцию, используя:

char* baseString = InfoFile_getValue(projectName, "base");
printf("Outside size: %d\n",sizeof(baseString));
printf("String address outside function: %p\n",baseString);
printf("%s\n", baseString);

Я скомпилировал это, используя флаги CC и ниже:

pkg-config --cflags gtk+-3.0 -Без несовместимых типов указателей -Wno-int-conversion -Wno-discarded-qualifiers pkg-config --libs gtk+-3.0 -lpthread -lm

И это дает следующие результаты:

Inside size: 8
String address inside function 0x5567d9ff4540
Outside size: 8
String address outside function: 0xffffffffd9ff4540
Naruszenie ochrony pamięci (zrzut pamięci)

Похоже, он обрезает этот адрес до 4 байт и добавляет к нему префикс 0xff, но я понятия не имею, почему, я никогда не сталкивался с такой проблемой. Любые предложения будут полезны.

sizeof(returnValue) = sizeof указателя, а не того, на что он указывает. Просто говорю. Не знаю, было ли это намерением, но это то, что вы получили независимо от этого.
WhozCraig 16.12.2020 10:33

Да, я хотел проверить размер указателя, чтобы убедиться, что он равен 8 байтам здесь и там. Просто чтобы убедиться.

Łukasz Strugała 16.12.2020 10:40

Обычно вы видите что-то подобное только тогда, когда вызывающий абонент не подготовлен должным образом к вызову. То есть он не является надлежащим прототипом и предполагает int возврат, который энтузиасты-предупредители «исправляют», жестко отбрасывая его. В таком случае, если int и char* имеют разные размеры (типично для платформ x64), фактически пожинаются только 32-битные 64-битные результаты; остаток берется из старшего бита фантома int. Но я не вижу здесь таких махинаций. С прототипом этот код выглядит корректно. Если то, что вы утверждаете, правда, это должно воспроизводиться с InfoFile_getValue в основном выпотрошенным. Это правда?

WhozCraig 16.12.2020 10:45

Спасибо, ребята, всем вам, вы такие быстрые! Да, я пропустил правильный прототип функции. InfoFile_getValue был в отдельном файле, и я забыл включить «infoFile.h». Мне нужно, наконец, научиться читать предупреждения или как-то относиться к неявному объявлению предупреждения как к ошибке. Еще раз спасибо, вы восхитительны!

Łukasz Strugała 16.12.2020 10:58

Хм. Ваш компилятор должен был сказать вам, что это отсутствует. Если нет, вам нужно поднять уровень предупреждения: -Wall -Wextra. И, конечно же, вам нужно позаботиться о предупреждениях.

Gerhardh 16.12.2020 11:01

Да, это выдало мне предупреждение, но я просто не читал его :/ Теперь я добавил -Werror-implicit-function-declaration, и это должно предотвратить подобные ошибки в будущем.

Łukasz Strugała 16.12.2020 11:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
127
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Кажется, вы получаете знаковое расширение младших 32 бит адреса. Просто дикая догадка, но я думаю, что компилятор увидел InfoFile_getValue как функцию, возвращающую int, в то время как указатели имеют длину 64 бита.

Правило состоит в том, что функция должна быть объявлена ​​до того, как она будет использована. Если это не так, C предполагает, что она объявлена ​​как int func(), то есть функция, принимающая любые параметры и возвращающая целое число. Вы должны убедиться, что у вас есть:

char* InfoFile_getValue(char* projectName, char* key);

перед функцией (возможно, основной), содержащей char* baseString = InfoFile_getValue(projectName, "base");

Я надеюсь, что у меня есть несколько учетных записей, чтобы загрузить ваш ответ. Именно из-за такого ответа chatgpt пока не может заменить stackoverflow.

Ryan Chen 24.03.2023 04:04

Это похоже на расширение знака, так что это очень похоже на неявную ошибку C90 int. То есть компилятор считает, что функция возвращает int со значением 0xd9ff4540, что в 32-битной системе, скорее всего, является отрицательным числом в дополнении до 2. Затем каким-то образом он преобразуется в 64-битный из-за %p, и вы получаете расширение знака.

Самый простой способ решить эту ошибку - прекратить использовать C90 уже, черт возьми, ему 30 лет, он сломан и опасен. Избавление от неявного int само по себе является достаточной причиной для переноса вашего кода на стандартный C.

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

Вы испытываете усечение значения и расширение знака из-за плохо подготовленного вызывающего абонента. т.е. вызывающая сторона не знает о фактическом типе возвращаемого значения функции из-за отсутствия надлежащего прототипа. Это может усугубить ситуацию, если вы не будете внимательно следить за C, особенно когда имеете дело с кодовой базой, которая, кажется, прекрасно работает на платформах, где int и void* имеют одинаковый размер.

Самый простой пример для воспроизведения этого приведен ниже и документирует то, что должно происходить.

main.c

#include <stdio.h>

int main()
{
    void *p = foo();
    printf("main: p = %p\n", p);
}

foo.c

#include <stdio.h>

void *foo()
{
    static int x;
    void *p = &x;
    printf("foo: p = %p\n", p);
    return p;
}

Выполнение приведенного выше кода после сборки как для x86 (где int и void* обычно имеют одинаковый размер), так и для x64 (где int обычно 32-битный, а void — 64-битный) выявит как проблему, так и тонкость того, как вы можете пропустить это в этом бывший случай. Оба должны отображать предупреждения, подобные этому (которые вы все равно должны рассматривать как ошибки)

1>main.c(13): warning C4013: 'foo' undefined; assuming extern returning int
1>main.c(13): warning C4047: 'initializing': 'void *' differs in levels of indirection from 'int'    

Результаты запуска на обеих платформах (очевидно, значения здесь могут различаться в вашей системе)

x86

foo: p = 00A38138
main: p = 00A38138

x64

foo: p = 00007FF7E7B0C160
main: p = FFFFFFFFE7B0C160

После этого вы, надеюсь, увидите, насколько важны две вещи:

  1. Всегда убедитесь, что функции, которые вы вызываете в исходном коде, правильно прототипированы перед их использованием.
  2. Всегда компилируйте с предупреждениями-как-ошибками, чтобы выявлять такие проблемы.

Вероятно, самая важная вещь, о которой следует помнить, это то, что если не выполнять оба пункта выше, код по-прежнему будет нормально работать на x86 и по-прежнему компилируется на x64. Первое может убаюкать вас ложным чувством выполненного долга, а второе только еще больше подтверждает это, делая поиск таких проблем особенно раздражающим. Позвольте компилятору помочь вам. Убедитесь, что (1) и (2) включены в вашу рутину.

Спасибо чувак, именно так и произошло. Я перехожу с x86 на x64 и после этого столкнулся с этой проблемой. Теперь я узнал кое-что новое и добавил -Werror-implicit-function-declaration, чтобы предотвратить подобные ошибки в будущем.

Łukasz Strugała 16.12.2020 11:18

Другие вопросы по теме