У меня странная проблема, я выделил память с помощью 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-qualifierspkg-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, но я понятия не имею, почему, я никогда не сталкивался с такой проблемой. Любые предложения будут полезны.
Да, я хотел проверить размер указателя, чтобы убедиться, что он равен 8 байтам здесь и там. Просто чтобы убедиться.
Обычно вы видите что-то подобное только тогда, когда вызывающий абонент не подготовлен должным образом к вызову. То есть он не является надлежащим прототипом и предполагает int возврат, который энтузиасты-предупредители «исправляют», жестко отбрасывая его. В таком случае, если int и char* имеют разные размеры (типично для платформ x64), фактически пожинаются только 32-битные 64-битные результаты; остаток берется из старшего бита фантома int. Но я не вижу здесь таких махинаций. С прототипом этот код выглядит корректно. Если то, что вы утверждаете, правда, это должно воспроизводиться с InfoFile_getValue в основном выпотрошенным. Это правда?
Спасибо, ребята, всем вам, вы такие быстрые! Да, я пропустил правильный прототип функции. InfoFile_getValue был в отдельном файле, и я забыл включить «infoFile.h». Мне нужно, наконец, научиться читать предупреждения или как-то относиться к неявному объявлению предупреждения как к ошибке. Еще раз спасибо, вы восхитительны!
Хм. Ваш компилятор должен был сказать вам, что это отсутствует. Если нет, вам нужно поднять уровень предупреждения: -Wall -Wextra. И, конечно же, вам нужно позаботиться о предупреждениях.
Да, это выдало мне предупреждение, но я просто не читал его :/ Теперь я добавил -Werror-implicit-function-declaration, и это должно предотвратить подобные ошибки в будущем.





Кажется, вы получаете знаковое расширение младших 32 бит адреса. Просто дикая догадка, но я думаю, что компилятор увидел InfoFile_getValue как функцию, возвращающую int, в то время как указатели имеют длину 64 бита.
Правило состоит в том, что функция должна быть объявлена до того, как она будет использована. Если это не так, C предполагает, что она объявлена как int func(), то есть функция, принимающая любые параметры и возвращающая целое число. Вы должны убедиться, что у вас есть:
char* InfoFile_getValue(char* projectName, char* key);
перед функцией (возможно, основной), содержащей char* baseString = InfoFile_getValue(projectName, "base");
Я надеюсь, что у меня есть несколько учетных записей, чтобы загрузить ваш ответ. Именно из-за такого ответа chatgpt пока не может заменить stackoverflow.
Это похоже на расширение знака, так что это очень похоже на неявную ошибку 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
После этого вы, надеюсь, увидите, насколько важны две вещи:
Вероятно, самая важная вещь, о которой следует помнить, это то, что если не выполнять оба пункта выше, код по-прежнему будет нормально работать на x86 и по-прежнему компилируется на x64. Первое может убаюкать вас ложным чувством выполненного долга, а второе только еще больше подтверждает это, делая поиск таких проблем особенно раздражающим. Позвольте компилятору помочь вам. Убедитесь, что (1) и (2) включены в вашу рутину.
Спасибо чувак, именно так и произошло. Я перехожу с x86 на x64 и после этого столкнулся с этой проблемой. Теперь я узнал кое-что новое и добавил -Werror-implicit-function-declaration, чтобы предотвратить подобные ошибки в будущем.
sizeof(returnValue)= sizeof указателя, а не того, на что он указывает. Просто говорю. Не знаю, было ли это намерением, но это то, что вы получили независимо от этого.