Is it possible to use for loop to reduce C code?

Asked

Viewed 138 times

3

I have the following function:To. It is possible to use for loop B to generate the declarations as in the function To? What to wear instead of printf to become a declaration?

printf("%s%i%s\n",ad1,i,ad2);

To

void functionX(unsigned int buf) {
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A15));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A14));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A13));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A12));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A11));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A10));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A9 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A8 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A7 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A6 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A5 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A4 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A3 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A2 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A1 ));
    H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A0 ));    
}

B

void functionX(unsigned int buf) {
    int i;
    char ad1[]="H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A";
    char ad2[]="));";

    for (i=15; i>=0; i--) {
      printf("%s%i%s\n",ad1,i,ad2);
    }
}

3 answers

6


How about something like this:

void functionX( unsigned int buf )
{
    int i;

    int addr[16] = { EEPROM_A15, EEPROM_A14, EEPROM_A13, EEPROM_A12,
                   EEPROM_A11, EEPROM_A10, EEPROM_A9, EEPROM_A8,
                   EEPROM_A7, EEPROM_A6, EEPROM_A5, EEPROM_A4,
                   EEPROM_A3, EEPROM_A2, EEPROM_A1, EEPROM_A0 };

    for( i = 0; i < 16; i++ ) {
        H8_3687_pulse( EEPROM_MASK( buf, addr[i] ) );
    }

}
  • Lacobus, no point! I will choose your answer! What is this solution called with array? Library, List?

3

Although ordinarily I follow Lacobus' response, this is a good place to remember that the compiler tcc has a dynamic link library that allows dynamic code compilation:

#include "libtcc.h"

void (*)(unsigned int)
compilar_funcao(TCCState * s) {
    char buffer[1024];
    char * ptr = buffer;

    /* monta o texto do programa */
    ptr += sprintf(ptr,
        "#include \"header.h\"\n" // cabeçalho com as definições de EEPROM_MASK e EEPROM_A*
        "void f(unsigned int buf) {\n"
    );
    for (int i = 15; i >= 0; i --) {
        ptr += sprintf(ptr,
            "H8_3687_pulse(EEPROM_MASK(buf, EEPROM_A%d));\n",
            i
        );
    }
    ptr += sprintf(ptr, "}");
    /* fornecer os caminhos para inclusão de cabeçalhos */
    tcc_add_include_path(s, "./"); /* aqui o diretório atual */
    /* compilar para a memória */
    tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
    if (tcc_compile_string(buffer) == 1)
        return NULL;
    /* resolver as referências a símbolos externos */
    tcc_add_symbol(s, "H8_3687_pulse", H8_3687_pulse);
    /* fazer a relocação (trabalho do linker) */
    if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0)
        return NULL;
    /* retornar o símbolo global compilado (neste caso, chamado f */
    return tcc_get_symbol(s, "f");
}

On startup/completion of the program you have to create the TCCState* to move to the function compilar_funcao() above:

int
main(int argc, char ** argv) {
    TCCState * s = tcc_new();
    /* resto do programa... */
    tcc_delete(s);
    return 0;
}

Of course, in this particular case is a Overkill tremendous, but it’s a good option if dynamic code generation cannot be avoided...

  • I did not know this option, very cool. In this case, the tcc you will need access to header.h in Runtime, right? Just put the file on the executable side?

  • 1

    @Jeffersonquesado: Actually, there is a call to establish the include path or the system include path that he will use to search for the headers. I will add in the answer. I suspect that, in Windows, it always looks in the current directory, but it does not cost to be explicit.

  • 1

    Very grateful Wtrmute and Jeffersonquesato, very good. I forgot to add that as I am addressing a Renesas H8/3687 microcontroller, I must use a Hitachi compiler. I don’t know yet if it is possible to use #include "libtcc. h". Let’s make contact with Renesas support today and get this. Big hug. I’ll choose Lacobus' answer.

3

You have a very special case there. I believe that EEPROM_A## be a family of macros. Macros work at the pre-processing level of the source file, a purely textual processing that takes place before calling the C compiler itself. I go into more detail about the preprocessor in this other answer.

In this case, there is not much to be done. At some point you need to access each of these macros... What can be done is to access these macros at an earlier time, populate a vector with these values.

If they are not macros, if they are variables, the language also does not provide any facility in relation to this. C is a compiled language, and the name of the variables serves only as a mnemonic so that the programmer (and the compiler as well) can call a memory region. After the compilation, the name ceases to exist and there is only the memory region, so there is not much to do about it.

In the case of variables, if they were compiled aligned as if they were an array, it is possible to use a few pointers to perform this operation on a loop. Recap: if the variables were compiled aligned as if they were a vector, something that depends on compiling the library from where you get these values. If you are compiling the library or if this is not explicitly written in its documentation, then we can assume that the following method is unreliable.

int i;
int *eeprom_a0_pt;

eeprom_a0_pt = &EEPROM_A0;

for (i = 15; i >= 0; i--) {
    H8_3687_pulse(EEPROM_MASK(buf, *(eeprom_a0_pt + i) ));
}

But you can only do this if and only if it is guaranteed that the variables were compiled aligned as if they were an array.

I looked for some alternative using the GCC extension of variadic macros, but I couldn’t find anything that could do this processing.


the section below was written before I became aware of tcc, serving then for traditional C with no external libraries; for more details, see Wtrmute

But why all this? Simple, by the design of the C language.

As I explained above, the name of the variables is lost in the compilation. If it is macro, the text substitution occurs before the compilation.

To do this take the exit from the printf and execute it correctly, you would need to evaluate (evaluate in English) the expression. Doing this evaluation is the equivalent of calling a compiler for that chunk of code, also known as calling the function eval available in some programming languages.

The practice of dynamic code generation to be evaluated in run time is typical of Lisp and Bash, not very common in C.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.