This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

What does the C standard say about portability?

Hello,

See here:

www.open-std.org/.../C99RationaleV5.10.pdf

Is it possible that "Jack Sprat", the staunch defender of the C standard as the ultimate reference when writing programs, missed the following statement?

C code can be non-portable.  Although it strove to give programmers the opportunity to write
truly portable programs, the C89 Committee did not want to force programmers into writing
portably, to preclude the use of C as a “high-level assembler”:  the ability to write machine-
35  specific code is one of the strengths of C.  It is this principle which largely motivates drawing the
distinction between strictly conforming program and conforming program (§4).

this is precisely what Per Westermark has been saying.
Exactly what Erik Malund has been saying.
Remember: Jack Sprat claims often that writing a program that complies with the C standard is a GUARANTEE for its correct functioning.

Parents
  • The first official case of modularizing is to produce a reusable and portable module for GPIO and key-input debouncing.

    For traditional PIC MCUs, they still believe that multi-layered structure of software design will work well. To me, multi-layered structure of software design leads to more depth of function calls and more RAM consumption.

Reply
  • The first official case of modularizing is to produce a reusable and portable module for GPIO and key-input debouncing.

    For traditional PIC MCUs, they still believe that multi-layered structure of software design will work well. To me, multi-layered structure of software design leads to more depth of function calls and more RAM consumption.

Children
  • Multi-layered, modularized, code can work very well. But it isn't always the best concept for a lamp timer or other projects with extremely little logic. It is a concept that assumes that the program have a bit of business logic - if it hasn't, then the size is probably so small that even badly modularized programs will be easy to maintain.

    Having GPIO in a module sounds like an incorrect slicing of the cake, but I might have misunderstood how it was planned. I normally create inline functions for getter/setter functions instead of trying to have a generic GPIO-read or GPIO-write.

    So a project may look like:

    activate_siren();
    activate_relay1();
    if (tamper_switch_active() {
        ...
    }
    

    The above makes it easy to change what pins that drives different things (and how the pins are driven) or how input stimuli is retrieved. Often, the same source code is compiled for multiple hardware platforms but the header file with all the inline functions is different.

    Since the inline functions may look like:

    __inline void activate_siren(void) {
        FIO1SET = 1u << P1_SIREN;
    }
    __inline void deactivate_siren(void) {
        FIO1CLR = 1u << P1_SIREN;
    }
    


    the efficiency is excellent.

    If trying to make the full GPIO into a generic module, that module must take parameters for the requested action, and decide what to actually do. It both takes extra code and extra clock cycles, without any gain. It is more likely to get the business logic intermixed with the decisions which actual pins that are used for different things.

    Code like: set_gpio_pin(GPIO_RELAY,GPIO_ON) requires the set_gpio_pin() function to figure out what port and pin to modify, and if the pin should be high and low (not trivial since some pins may require inverted logic depending on external electronics).

    And code like set_gpio0_pin(GPIO0_RELAY,GPIO_ON) will save the generic function from knowing what port is involved - but will instead require that the business logic is modified if the function is moved to a pin on a different port.

    Having C files that don't include a corresponding header file with the exported symbols sounds like a big mental accident. C++ can catch some problems thanks to the type safe linking. But for C, the problems will quickly be catastrophic unless a code analyzer with global processing capabilities is used.

    I see the header file as a form of "contract". It contains a list of services that the C module promises to deliver. Obviously, the module itself should also be allowed to know what services it promises to deliver.

    I'm not so sure about the suitability of having a generic keyboard debounce to plug into all projects. A big question is where the debounce code would get the information about time. Another is that some projects may have single buttons (ENTER, BACK, LEFT, RIGHT) connected to individual processor pins, while other projects may have a matrix keyboard where the user may hold more than one button pressed. Having fully generic code for a 4x4 keyboard would also be interesting since it then would basically have to to read and set pins one-by-one using the GPIO layer - the GPIO layer would have to be extremely advanced to support simultaneous sampling of controlling of multiple pins.

    In many situations, you perform modularization by calling a standard function name, to get something done, but then have multiple implementations depending on project. This is normal way to implement serial communication - each target processor have one source file for each supported serial port, and the program just uses com0_sendchar() or com0_printf().

    But trying to code something hardware-specific into a generic function either leads to lots of conditional compilation or into lots of really meaningless glue functions being created and called. How fun would it be with a generic UART driver that contains code for:

    f = get_base_frequency();
    idiv = get_uart_ticks_per_bit();
    divisor = f / idiv / baud;
    error = f - divisor * idiv*baud;  // might need fractional baudrate compensation
    set_baud_divisor(divisor,error);
    

    Too generic will quickly explode into unmaintainable, large and inefficient solutions.

  • The C unfriendly architecture of the traditional PIC MCU makes things worse.

    Although I am not a competent developer, and I am not good at explaining and illustrating, but it is quite easy to know that, people here will fail.

    I am not able to do much to help people here. Because they are numerous, and in higher position.

    Maybe Bill Gates or Steve Jobs can convince them, but Dennis Ritchie and Ken Thompson can NOT.

  • "multi-layered structure of software design leads to more depth of function calls and more RAM consumption."

    absolutely true.

    that's why we live, unfortunately, in a world where people are paid big $$$$$ to make the right compromise.

    engineering a non-compromised design is simple - because you will never get it done.

    it is engineering a compromised design that is incredibly hard.

  • "Too generic will quickly explode into unmaintainable, large and inefficient solutions."

    because being unmaintainable, large and inefficient is how you define something to be too generic. so the above sentence is meaningless.

    there is always a degree of "optimization" or compromise here. the fact that an approach, when pushed to an extreme, can be unmaintainable, large and inefficient doesn't mean that that approach is unmaintainable, large and inefficient.

    it only means that you have made a poor compromise. so in that case, blame the person(s) pushing that approach to be unmaintainable, large and inefficient, not that approach.

  • "I am not able to do much to help people here. Because they are numerous, and in higher position."

    given enough time, they will move up the value chain and learn how to make the right compromises.

    hopefully, in the mean time, we have moved onto something more difficult and more value-added.

  • "Too generic will quickly explode into unmaintainable, large and inefficient solutions."
    
    because being unmaintainable, large and inefficient is how you define something to be too
    generic. so the above sentence is meaningless.
    


    You just turned the direction on an implication arrow, or upgraded a one-way relation into a two-way equivalence.

    A too general solution gets unmaintainable, large and inefficient.

    But a unmaintainable code block need not be too general, or even general at all.
    A large code block need not be too general, or even general at all.
    A inefficient block need not be too general, or even general at all.

    So, in short, your summary that the above sentence is meaningless is based on erroneous logic.

    => does not imply <= or <=>

  • because being unmaintainable, large and inefficient is how you define something to be too generic
    

    Well well, this is a rather artistic license to define "too generic".
    Why "unmaintainable" ?
    Why "inefficient" ?
    And why "large"?

    None of the above _necessarily_ true.

  • "A too general solution gets unmaintainable, large and inefficient."

    I am not sure what a too "general" solution is: I thought we were talking about code being too "generic" (not "general").

    if you object to my approach, then what do you mean by "too generic"?