2009-05-25 36 views
22
incrustado

Chicos, quiero saber si las variables float se pueden usar en la función sprintf().Uso de flotadores con sprintf() en C

Al igual que, si escribimos:

sprintf(str,"adc_read = %d \n",adc_read); 

donde adc_read es una variable entera, se va a almacenar la cadena

"adc_read = 1023 \n"

en str (suponiendo que adc_read = 1023)

¿Cómo puedo usar una variable flotante en lugar de un entero?

+0

Lo C-biblioteca se le vincula en contra? – sybreon

+1

Tenga en cuenta que está tratando de formatear un doble. Con varargs el compilador automáticamente promocionará un valor flotante al doble. – Richard

+3

"Embedded", muchachos. Esa es la clave. No importa lo que sus bibliotecas de lujo-shmancy hagan en sus máquinas con GB de memoria :-) Las plataformas integradas generalmente tienen ventajas y desventajas con el objetivo de minimizar la huella de memoria. – paxdiablo

Respuesta

40

Dado que está en una plataforma integrada, es muy posible que no tenga todas las capacidades de las funciones de estilo printf().

Asumiendo que tiene flotadores en absoluto (todavía no necesariamente un dadas para la materia integrado), puede emular con algo como:

char str[100]; 
float adc_read = 678.0123; 

char *tmpSign = (adc_read < 0) ? "-" : ""; 
float tmpVal = (adc_read < 0) ? -adc_read : adc_read; 

int tmpInt1 = tmpVal;     // Get the integer (678). 
float tmpFrac = tmpVal - tmpInt1;  // Get fraction (0.0123). 
int tmpInt2 = trunc(tmpFrac * 10000); // Turn into integer (123). 

// Print as parts, note that you need 0-padding for fractional bit. 

sprintf (str, "adc_read = %s%d.%04d\n", tmpSign, tmpInt1, tmpInt2); 

Tendrá que restringir el número de caracteres vienen después del punto decimal basa en los tamaños de tus enteros.Por ejemplo, con un entero con signo de 16 bits, está limitado a cuatro dígitos (9.999 es la mayor potencia de diez menos uno que se puede representar).

Sin embargo, hay formas de manejar esto procesando aún más la parte fraccionaria, cambiándola por cuatro dígitos decimales cada vez (y usando/restando la parte entera) hasta que tenga la precisión que desea.


Actualización:

Un punto final que usted ha mencionado que estaba utilizando avr-gcc en una respuesta a una de las otras respuestas. Encontré la siguiente página web que parece describir lo que necesita hacer para usar %f en sus declaraciones printf()here.

Como sospechaba originalmente, necesita hacer un poco de trabajo extra para obtener soporte de punto flotante. Esto se debe a que las cosas integradas raramente necesitan punto flotante (al menos ninguna de las cosas que he hecho alguna vez). Implica establecer parámetros adicionales en su archivo MAKE y vincularlos con bibliotecas adicionales.

Sin embargo, es probable que aumente un poco el tamaño del código debido a la necesidad de manejar formatos de salida generales. Si puedes restringir tus salidas de flotación a 4 lugares decimales o menos, te sugiero convertir mi código en una función y solo usar eso, es probable que ocupe mucho menos espacio.

En caso de que el enlace nunca desaparece, lo que tiene que hacer es asegurarse de que su comando gcc tiene "-Wl,-u,vfprintf -lprintf_flt -lm" Esto se traduce en:.

  • fuerza vfprintf que no está definido inicialmente (de modo que el enlazador tiene que resolver ella).
  • especificar la biblioteca de punto flotante printf() para la búsqueda.
  • especifique la biblioteca matemática para la búsqueda.
+0

que es un buen truco, voy a tratar a cabo Gracias – aditya

+0

está dando error de compilación de error: se esperaba expresión antes 'int' en código anterior en la línea 5 – aditya

+0

Lo siento, demasiado Java. Ver actualización – paxdiablo

0

utiliza el %f modificador:

sprintf (str, "adc_read = %f\n", adc_read); 

Por ejemplo:

#include <stdio.h> 

int main (void) 
{ 
    float x = 2.5; 
    char y[200]; 

    sprintf(y, "x = %f\n", x); 
    printf(y); 
    return 0; 
} 

Rendimientos esto:

x = 2.500000

+1

lo hice, pero no funcionó \t imprime un? carácter en lugar de la cadena – aditya

-2

Sí, utilizar% f

+0

Lo hice, pero no funcionó – aditya

+1

imprime un? personaje en lugar de la cadena. – aditya

+0

¿Cómo no funcionó? Salida incorrecta? – rein

0

Sí, por supuesto, hay no es nada especial con flotadores. Puede usar cadenas de formato como las utiliza en printf() para flotantes y cualquier otro tipo de datos.

EDITAR yo probamos este código de ejemplo:

float x = 0.61; 
char buf[10]; 
sprintf(buf, "Test=%.2f", x); 
printf(buf); 

salida fue: Prueba = 0,61

+0

Sí, pero no funcionó \t imprime un? carácter en lugar de la cadena – aditya

+0

Ver la edición de mi código de muestra ... Tengo la sensación de que su búfer "str" ​​es demasiado pequeño. No use algo similar% .2f para establecer la precisión. – Naveen

+0

tamaño de mi búfer es 100 en realidad, lo estoy imprimiendo en un puerto serie, así que creo que el problema está en transmitir variables flotantes en UART – aditya

2

Sí se puede. Sin embargo, depende de la biblioteca C a la que se está vinculando y debe ser consciente de las consecuencias.

Como está programando para aplicaciones integradas, tenga en cuenta que se emula el soporte de coma flotante para muchas arquitecturas integradas. Compilar en este soporte de punto flotante terminará aumentando el tamaño de su ejecutable significativamente.

+0

estoy usando avr-gcc – aditya

1

No esperes que sprintf (o cualquier otra función con varargs) genere automáticamente algo. El compilador no intenta leer la cadena de formato y hacer el molde por usted; en tiempo de ejecución, sprintf no tiene metainformación disponible para determinar qué hay en la pila; simplemente muestra bytes y los interpreta como dados por la cadena de formato. sprintf (myvar, "% 0", 0); inmediatamente segfaults.

Entonces: ¡Las cadenas de formato y los otros argumentos deben coincidir!

0

Si y no. A pesar de lo que algunas otras respuestas han dicho, el compilador de C es necesario para realizar las conversiones de sprintf(), y todas las demás funciones variadic, de la siguiente manera:

  • char =>int
  • short =>int
  • float =>double

(y las variantes firmadas/sin firmar del ab tipos integrales ove)

Hace esto precisamente porque sprintf() (y las otras print() -funciones de la familia) serían inutilizables sin él. (Por supuesto, they're pretty unusable as it is.)

Pero no puede asumir ninguna otra conversión, y su código tendrá un comportamiento indefinido, léase: ¡bloqueo! - Si lo haces.

+1

Se requiere que el compilador para realizar _conversions_. Un _cast_ es explícitamente solicitado por el programador. – mlp

+0

justo comentario. corrigiendo ahora – dcw

+1

"Inutilizable" es una palabra bastante fuerte. La familia printf() es bastante útil, pero no es perfecta. Tiene obvios defectos de seguridad tipo, pero el compilador puede verificar fácilmente los tipos de argumentos que está aprobando en el 99% de los casos de uso y le da una advertencia/error (vea gcc's -Wformat et al). –

0

Busque en la documentación de sprintf para su plataforma. Por lo general, es% f o% e. El único lugar donde encontrará una respuesta definitiva es la documentación ... si no está documentado, todo lo que puede hacer es ponerse en contacto con el proveedor.

¿Qué plataforma es? Alguien ya podría saber dónde están los documentos ... :)

+0

es el microcontrolador Atmega128 El compilador es avr-gcc. Gracias por la respuesta, pero la respuesta dada por Pax funcionó a la perfección. – aditya

0

No haga esto; los enteros en C/C++ siempre se redondean hacia abajo para que no haya necesidad de usar la función de piso.

char str[100]; 
int d1 = value; 

mejor utilizar

int d1 = (int)(floor(value)); 

Entonces usted no conseguirá redondeo de la parte entera (68.9999999999999999 convierte 69.00 ..). 68.09999847 en lugar de 68.1 es difícil de evitar: cualquier formato de coma flotante tiene una precisión limitada.

3

no es algo como esto muy fácil:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

char str[10]; 
float adc_read = 678.0123; 

dtostrf(adc_read, 3, 4, temp); 
sprintf(str,"adc_read = %10s \n", temp); 
printf(temp); 
+0

sí me funcionó muy bien después de horas de búsqueda, gracias –

+0

Es más fácil, pero no funciona si no puedes insertar stdlib porque estás apuntando a un pequeño microcontrolador. – Funkodebat

0

% g puede hacer esto:

#include <stdio.h> 
int main() { 
    float w = 234.567; 
    char x[__SIZEOF_FLOAT__]; 
    sprintf(x, "%g", w); 
    puts(x); 
}