Функция, возвращающая неправильное значение, в C, используя компилятор gcc Intel - PullRequest
2 голосов
/ 23 октября 2011

Я пишу это, потому что я действительно не знаю, почему это происходит. Я знаю, как это исправить / обойти это, но я хотел бы знать причину, по которой это происходит. Я использую C, и мой компилятор - gcc 4.4.1 (TDM), работающий на машине Intel.

Допущения относительно поплавков: -Соответствовать стандарту IEEE 754 - хранятся в формате Big Endian

Давайте предположим, что у нас есть функция, принимающая массив из 4 байтов и возвращающая их как число с плавающей точкой. Это цель функции. Скажем также, что, например, все, что будет делать функция, - это получать байты в «правильном порядке», а поскольку система имеет младший порядок, она просто поменяет их местами и поместит их в число с плавающей точкой, чтобы вернуть значение. Для простоты я не включаю какие-либо проверки для NaN или INF, поскольку это не является целью этого вопроса.

float testFunction(char* arr)
{
    //this will be the float we return
    float ret;

    //let's just get a char pointer to the float so we can alter its byte values
    char* c = (char*)&ret;
    //just swap them so they conform with little endian byte order
    c[0] = arr[3];
    c[1] = arr[2];
    c[2] = arr[1];
    c[3] = arr[0];

    //up to here if you debug and watch ret's value it is correct as it is supposed to be
    return ret;
}

Проблема в том, где я использую функцию ... скажем, как показано ниже

   float f = testFunction(arr);

Тогда число с плавающей запятой f имеет совершенно несущественное значение для чисел с байтами, которые вы передаете в качестве параметров.

Способ успешно обойти это состоит в том, чтобы объявить функцию, которая принимает значение с плавающей точкой в ​​качестве параметра и присваивает ему значение внутри функции следующим образом:

void testFunction(char* arr,float* f)
{
   char* c = ((char*)f)
   c[0] = arr[3];
   c[1] = arr[2];
   c[2] = arr[1];
   c[3] = arr[0];
 }

Но все же мой вопрос: почему это происходит, когда я пытаюсь вернуть значение? Я понимаю, что float ret является временным значением внутри области функции, но оператор return должен копировать его значение за пределы функции. Разве это не правильно? Что мне не хватает? Я думаю, это должно быть что-то действительно очевидное.

Ответы [ 3 ]

4 голосов
/ 23 октября 2011

На самом деле в обоих случаях значение с плавающей точкой должно иметь «совершенно не относящееся к делу» значение, если только вы тщательно не обработаете этот набор символов (например, memcpy из float).

Вы не можете просто установить байты и надеяться, что он будет волшебным образом соответствовать представлению на вашей платформе.

2 голосов
/ 23 октября 2011

Я скажу что-нибудь глупое. Но попробуйте инициализировать ret, например float ret = 0;.

Я не уверен, что вы можете инициализировать переменную "piecemail" по одной char за раз и считать ее "инициализированной" для стандарта C (и компилятора)

2 голосов
/ 23 октября 2011

WAG. Из-за приведения типов компилятор не распознает, что переменная f была обновлена. Для компилятора нет связи между переменной f и указателем c. Он не знает, что это псевдоним. Как и в ABI, float возвращается в регистр, он должен генерировать загрузку из стека, когда он делает return, но, поскольку он видит, что f унифицирован, он ничего не делает и возвращает случайное содержимое регистра используется для этого. Если вы объявите float как volatile, это должно сделать то, что вы ожидаете.

Как уже говорилось, это дикое предположение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...