Если у вас нет доступа к подпрограммам .Net, то это сложно. Я сделал это сам для своего шестнадцатеричного редактора (чтобы пользователи могли отображать и редактировать десятичные значения C # с помощью диалога свойств) - см. http://www.hexedit.com для получения дополнительной информации. Также источник для HexEdit находится в свободном доступе - см. Мою статью на http://www.codeproject.com/KB/cpp/HexEdit.aspx.
На самом деле мои процедуры конвертируются между десятичным и строковым значениями, но вы, конечно, можете сначала использовать sprintf для преобразования двойного в строковое значение. (Также, когда вы говорите о double, я думаю, вы явно имеете в виду 64-битный формат IEEE с плавающей запятой, хотя это то, что в настоящее время используется большинством компиляторов / систем.)
Обратите внимание, что есть несколько ошибок, если вы хотите точно обработать все допустимые десятичные значения и вернуть ошибку для любого значения, которое не может быть преобразовано, так как формат плохо документирован. (Десятичный формат действительно ужасен, например, одно и то же число может иметь много представлений.)
Вот мой код, который преобразует строку в десятичную. Обратите внимание, что в нем используется арифметическая библиотека GNU Multiple Precision (функции, начинающиеся с mpz_). Функция String2Decimal, очевидно, возвращает false, если по какой-то причине происходит сбой, например, слишком большое значение. Параметр «presult» должен указывать на буфер размером не менее 16 байт, чтобы сохранить результат.
bool String2Decimal(const char *ss, void *presult)
{
bool retval = false;
// View the decimal (result) as four 32 bit integers
unsigned __int32 *dd = (unsigned __int32 *)presult;
mpz_t mant, max_mant;
mpz_inits(mant, max_mant, NULL);
int exp = 0; // Exponent
bool dpseen = false; // decimal point seen yet?
bool neg = false; // minus sign seen?
// Scan the characters of the value
const char *pp;
for (pp = ss; *pp != '\0'; ++pp)
{
if (*pp == '-')
{
if (pp != ss)
goto exit_func; // minus sign not at start
neg = true;
}
else if (isdigit(*pp))
{
mpz_mul_si(mant, mant, 10);
mpz_add_ui(mant, mant, unsigned(*pp - '0'));
if (dpseen) ++exp; // Keep track of digits after decimal pt
}
else if (*pp == '.')
{
if (dpseen)
goto exit_func; // more than one decimal point
dpseen = true;
}
else if (*pp == 'e' || *pp == 'E')
{
char *end;
exp -= strtol(pp+1, &end, 10);
pp = end;
break;
}
else
goto exit_func; // unexpected character
}
if (*pp != '\0')
goto exit_func; // extra characters after end
if (exp < -28 || exp > 28)
goto exit_func; // exponent outside valid range
// Adjust mantissa for -ve exponent
if (exp < 0)
{
mpz_t tmp;
mpz_init_set_si(tmp, 10);
mpz_pow_ui(tmp, tmp, -exp);
mpz_mul(mant, mant, tmp);
mpz_clear(tmp);
exp = 0;
}
// Get max_mant = size of largest mantissa (2^96 - 1)
//mpz_set_str(max_mant, "79228162514264337593543950335", 10); // 2^96 - 1
static unsigned __int32 ffs[3] = { 0xFFFFffffUL, 0xFFFFffffUL, 0xFFFFffffUL };
mpz_import(max_mant, 3, -1, sizeof(ffs[0]), 0, 0, ffs);
// Check for mantissa too big.
if (mpz_cmp(mant, max_mant) > 0)
goto exit_func; // value too big
else if (mpz_sgn(mant) == 0)
exp = 0; // if mantissa is zero make everything zero
// Set integer part
dd[2] = mpz_getlimbn(mant, 2);
dd[1] = mpz_getlimbn(mant, 1);
dd[0] = mpz_getlimbn(mant, 0);
// Set exponent and sign
dd[3] = exp << 16;
if (neg && mpz_sgn(mant) > 0)
dd[3] |= 0x80000000;
retval = true; // indicate success
exit_func:
mpz_clears(mant, max_mant, NULL);
return retval;
}