elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: ¿Eres nuevo? ¿Tienes dudas acerca del funcionamiento de la comunidad? Lee las Reglas Generales


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  [c++11] ¿Como pasar n argumentos a una función?
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: [c++11] ¿Como pasar n argumentos a una función?  (Leído 3,388 veces)
carl0s_47

Desconectado Desconectado

Mensajes: 2


Ver Perfil
[c++11] ¿Como pasar n argumentos a una función?
« en: 8 Marzo 2017, 05:07 am »

Que tal,

Es mi primer pregunta acá, se un poco de C y estoy intentando aprender a programar C++ "moderno" de forma autodidacta y es mi primer proyecto "útil", así que estaré atento a consejos para mejorarlo xD.

Quiero diseñar una GUI (con Qt) con la cual pueda mandarle datos a un microcontrolador por puerto serial, con estos datos se van a configurar varios registros de un sensor que esta conectado al microcontrolador.

El sensor tiene varios registros, cada registro tiene varios campos y cada campo tiene varios valores   que cambian la configuración del sensor, en la siguiente imagen se pueden ver el registro CONFIG_0 y sus campos NUM_TX y TX_FREQ_DIV:



Para representar cada campo del registro utilice un std::map, la llave (key) es el número que se le escribirá al campo en el registro (por ejemplo de 0 a 7 en TX_FREQ_DIV) y el valor (value) es la descripción de cada llave ("Divide by 2", "Divide by 4", etc.), el contenido de cada uno de estos campos los agrego a un combobox de Qt.

Cada registro del sensor puede tener un número diferente de campos, hay registros con dos campos y otros con 3, 4, etc., así que hice una clase básica:

m_register.h
Código
  1. #ifndef M_REGISTER_H
  2. #define M_REGISTER_H
  3.  
  4. #include <QString>
  5. #include <map>
  6.  
  7. class m_register
  8. {
  9.    QString m_Name;
  10.    std::map<int, QString> m_Field_1;
  11.    std::map<int, QString> m_Field_2;
  12.    std::map<int, QString> m_Field_3;
  13.  
  14. public:
  15.    m_register(QString name) : m_Name(name) {}
  16.    QString getName(void) const;
  17.    void setField_1(const std::map<int, QString> field);
  18.    std::map<int, QString> getField_1(void) const;
  19.    void setField_2(const std::map<int, QString> field);
  20.    std::map<int, QString> getField_2(void) const;
  21.    void setField_3(const std::map<int, QString> field);
  22.    std::map<int, QString> getField_3(void) const;
  23. };
  24.  
  25. #endif // M_REGISTER_H
  26.  

m_register.cpp
Código
  1. #include "m_register.h"
  2.  
  3. QString m_register::getName() const
  4. {
  5.    return m_Name;
  6. }
  7.  
  8. void m_register::setField_1(const std::map<int, QString> field)
  9. {
  10.    m_Field_1 = field;
  11. }
  12.  
  13. std::map<int, QString> m_register::getField_1() const
  14. {
  15.    return m_Field_1;
  16. }
  17.  
  18. void m_register::setField_2(const std::map<int, QString> field)
  19. {
  20.    m_Field_2 = field;
  21. }
  22.  
  23. std::map<int, QString> m_register::getField_2() const
  24. {
  25.    return m_Field_2;
  26. }
  27.  
  28. void m_register::setField_3(const std::map<int, QString> field)
  29. {
  30.    m_Field_3 = field;
  31. }
  32.  
  33. std::map<int, QString> m_register::getField_3() const
  34. {
  35.    return m_Field_3;
  36. }
  37.  

Se ve que los métodos setField y getField de cada campo hacen lo mismo, mi duda es si es posible hacer una sola función que acepte n argumentos (n campos) y cree el mismo número de variables de tipo std::map.
¿Podría inicializar un vector sin especificar cuantos elementos contiene y especificar su tamaño en el constructor de m_register?.

He visto que para métodos con número de argumentos variables utilizan ... (olvide el nombre de esos tres puntos) pero no termino de entenderlos, ¿funcionan como argc y argv?

Así va mi GUI xD:


El grupo de arriba es de una prueba que hice sin la clase y el de abajo es una variable de tipo m_register.

Saludos


En línea

class_OpenGL


Desconectado Desconectado

Mensajes: 437

Si usas Direct3D, no eres mi amigo :P


Ver Perfil
Re: [c++11] ¿Como pasar n argumentos a una función?
« Respuesta #1 en: 8 Marzo 2017, 09:25 am »

Yo tampoco sé el nombre de los tres puntos, pero el tema va así:

Existe una librería de C (por lo que también está para C++) que se llama cstdarg. Esta es la que te permite pasar n parámetros. Cuando pasas un número indeterminado de parámetros, la función no sabe cuántos parámetros hay o de qué tipo son, además no sabe donde comienzan en memoria por lo que esas tres cosas se deberían indicar con un parámetro de la función. Por ejemplo, voy a hacer una función que acepte n parámetros y que haga la media aritmética:

Código
  1. #include <iostream>
  2. #include <cstdarg>
  3.  
  4. // La función solo aceptará doubles, así que el tipo viene implícito en la función.
  5. // La dirección de memoria de los parámetros la sabes gracias al último parámetro
  6. // (el que hay antes de los ...). En este caso, num_elementos. Esto implica que al menos
  7. // necesitar un parámetro en la función (en este caso, num_elementos).
  8. double MediaAritmetica(int num_elementos, ...) {
  9. va_list parametros;
  10. double parametro_actual;
  11. double media;
  12. int i;
  13.  
  14. va_start(parametros, num_elementos); // Inicializamos 'parametros' usando el último parámetro.
  15.  
  16. for(i = 0; i < num_elementos; i++) {
  17. parametro_actual = va_arg(parametros, double); // Obtenemos el siguiente parámetro, de tipo double.
  18. media += parametro_actual;
  19. }
  20.  
  21. media /= num_elementos;
  22. va_end(parametros); // No sé muy bien por qué, pero esta línea es necesaria.
  23.  
  24. return media;
  25. }
  26.  
  27. int main() {
  28. double media;
  29.  
  30. media = MediaAritmetica(4, 3.2, 1.1, 4.3, 2.0);
  31.  
  32. std::cout << media << std::endl;
  33.  
  34. return 0;
  35. }


En línea

Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL
MAFUS


Desconectado Desconectado

Mensajes: 1.603



Ver Perfil
Re: [c++11] ¿Como pasar n argumentos a una función?
« Respuesta #2 en: 8 Marzo 2017, 12:17 pm »

Lo más sensato sería que representaras el sensor en tu código, así, incluso, te sería más fácil depurar.

C, y por ende C++ son lenguajes creados para hablar con la máquina pero muchas veces, sobre todo quien trabaja a más alto nivel olvida o desconoce ese potencial del lenguaje. En tu caso deberías usar los bitfields.

En tu ejemplo, para representar el registro CONFIG_0 podrías hacer así:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. typedef enum {
  5.    DIVIDE_BY_2,
  6.    DIVIDE_BY_4,
  7.    DIVIDE_BY_8,    /* Default value */
  8.    DIVIDE_BY_16,
  9.    DIVIDE_BY_32,
  10.    DIVIDE_BY_64,
  11.    DIVIDE_BY_128,
  12.    DIVIDE_BY_256
  13. } prescaler;
  14.  
  15. struct {
  16.    unsigned TX_FREQ_DIV : 3;
  17.    unsigned NUM_TX : 5;
  18. } CONFIG_0;
  19.  
  20. /* Aquí otros registros
  21. struct {
  22.     unsigned <campo> : <tamaño en bits>;
  23.     unsigned <campo> : <tamaño en bits>;
  24.     ...
  25. } <nombre del registro>
  26.  
  27. ...
  28.  
  29. */
  30.  
  31. int main() {
  32.    CONFIG_0.TX_FREQ_DIV = DIVIDE_BY_8;
  33.    CONFIG_0.NUM_TX = 5;
  34.  
  35.    puts("CONFIG_0 register status");
  36.    puts("------------------------");
  37.    printf("TX_FREQ_DIV : %u\n", CONFIG_0.TX_FREQ_DIV);
  38.    printf("NUM_TX      : %u\n", CONFIG_0.NUM_TX);
  39. }
  40.  
En línea

ivancea96


Desconectado Desconectado

Mensajes: 3.412


ASMático


Ver Perfil WWW
Re: [c++11] ¿Como pasar n argumentos a una función?
« Respuesta #3 en: 8 Marzo 2017, 13:45 pm »

Si pones un ejemplo del código en el que uses los métodos de la clase m_register, se me despejarían algunas dudas.
No estoy seguro de que realmente te interese una función variadic.
Si quieres comprimir los 3setters y los 3 getters en 1 setter y 1 getter, podrías meter los 3 maps en un array (o en una std::list si te interesa que sea una cantidad de maps variable (o std::vector, vaya, según necesidades)), y en los setters/getters, recibir como parámetro el índice del map.

Si aun quieres utilizar un método variadic, ver un ejemplo de uso sería muy explicativo.
Y por cierto, ¿qué valores almacenas exactamente en el map?
En línea

carl0s_47

Desconectado Desconectado

Mensajes: 2


Ver Perfil
Re: [c++11] ¿Como pasar n argumentos a una función?
« Respuesta #4 en: 8 Marzo 2017, 17:26 pm »

Que tal,

Por ahora utilizo la clase solo para llenar de información a la ventana, la primer parte del constructor MainWindow le paso la información al grupo CONFIG_0, con la clase paso la información a CONFIG_0_c.

Código
  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3.  
  4. #include <QDebug>
  5. #include <QString>
  6.  
  7. #include <map>
  8.  
  9. #include "m_register.h"
  10.  
  11. MainWindow::MainWindow(QWidget *parent) :
  12.    QMainWindow(parent),
  13.    ui(new Ui::MainWindow)
  14. {
  15.    ui->setupUi(this);
  16.  
  17.    ui->groupBox->setTitle("CONFIG_0");
  18.    ui->label->setText("NUM_TX");
  19.    ui->label_2->setText("TX_FREQ_DIV");
  20.  
  21.    const std::map<int, QString> NUM_TX{{0, "0 Pulses"}, {1, "1 Pulse"}, {2, "2 Pulses"}, {3, "3 Pulse"}, {4, "4 Pulses"}, {5, "5 Pulses"},
  22.                                        {6, "6 Pulses"}, {7, "7 Pulse"}, {8, "8 Pulses"}, {9, "9 Pulse"}, {10, "10 Pulses"}, {11, "11 Pulses"},
  23.                                        {12, "12 Pulses"}, {13, "13 Pulse"}, {14, "14 Pulses"}, {16, "16 Pulse"}, {17, "17 Pulses"}, {18, "18 Pulses"},
  24.                                        {19, "19 Pulses"}, {20, "20 Pulse"}, {21, "21 Pulses"}, {22, "22 Pulse"}, {23, "23 Pulses"}, {24, "24 Pulses"},
  25.                                        {25, "25 Pulses"}, {26, "26 Pulse"}, {27, "27 Pulses"}, {28, "28 Pulse"}, {29, "29 Pulses"}, {30, "30 Pulses"},
  26.                                        {31, "31 Pulses"}, {32, "32 Pulse"}, {33, "33 Pulses"}, {34, "34 Pulse"}, {35, "35 Pulses"}};
  27.  
  28.    const std::map<int, QString> TX_FREQ_DIV{{0, "Divide by 2"}, {1, "Divide by 4"}, {2, "Divide by 8"}, {3, "Divide by 16"},
  29.                                             {4, "Divide by 32"}, {5, "Divide by 64"}, {6, "Divide by 128"}, {7, "Divide by 256"}};
  30.  
  31.    for(auto const& it : NUM_TX){
  32.        ui->comboBox->addItem(it.second);
  33.    }
  34.  
  35.    for(auto const& it : TX_FREQ_DIV){
  36.        ui->comboBox_2->addItem(it.second);
  37.    }
  38.  
  39.    // Usando la clase
  40.  
  41.    m_register m_config_0{"CONFIG_0_c"};
  42.    m_config_0.setField_1(NUM_TX);
  43.    m_config_0.setField_2(TX_FREQ_DIV);
  44.  
  45.    ui->groupBox_2->setTitle(m_config_0.getName());
  46.    ui->label_3->setText("NUM_TX_c");
  47.    ui->label_4->setText("TX_DIV_DIV_c");
  48.  
  49.    for(auto const& it : m_config_0.getField_1()){
  50.        ui->comboBox_3->addItem(it.second);
  51.    }
  52.  
  53.    for(auto const& it : m_config_0.getField_2()){
  54.        ui->comboBox_4->addItem(it.second);
  55.    }
  56.  
  57. }
  58.  
  59. MainWindow::~MainWindow()
  60. {
  61.    delete ui;
  62. }
  63.  

Me falta añadir una variable que guarde la locación del campo (a partir de que bit empieza), entonces podría hacer un struct con el std::map y la posición, y en la clase m_register tener un vector de este struct.

Saludos
En línea

ivancea96


Desconectado Desconectado

Mensajes: 3.412


ASMático


Ver Perfil WWW
Re: [c++11] ¿Como pasar n argumentos a una función?
« Respuesta #5 en: 8 Marzo 2017, 18:40 pm »

Ya que lso números son contiguos de 0 a N, en vez de un map, tal vez te interese utilizar un vector o una list.

A parte de eso, sobre el método variadic, lo dicho. Si puedes, pon un ejemplo de cómo usarías el método variadic con una cantidad indefinida de argumentos. No digo que lo hagas, sinó que lo utilices como si existiera para saber qué quieres hacer con él.
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines