如何使用C99标准型跨大多数平台最大的可移植性和效率? [英] How to use C99 standard types for maximum portability AND efficiency across most platforms?

查看:172
本文介绍了如何使用C99标准型跨大多数平台最大的可移植性和效率?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,这里是我的理解和思考什么是问题的真正的。


  1. 使用单变量,如柜台或循环指标快速的数据类型。例如:

     的#define LOOP_COUNT(100U)uint_fast8_t指数;
    对于(指数= 0;指数 - LT; LOOP_COUNT;指数++){
        /* 做一点事 */
    }

    我想在这里最合适的类型为 uint_fast8_t ,因为首页不能超过255个,这将是最快的实现所有平台。如果我用 unsigned int类型来代替,这将是> = 16位平台上最快的,但将上述&lt较慢; 16位平台为 INT 是最低标准由16位。另外,如果我用 uint8_t有它会慢于> 8位的平台,因为编译器增加了一个到0xFF 指令检查溢出每个增量(我的ARM7编译器,即使在全速优化)。 为size_t 也不是一个选项,因为它可以比原生的整数大小大。

    如果溢出预计为8位的这为侧(?),则不会发生。程序员应该检查手动溢出(因为他/她应该恕我直言),这可能会导致马车code。如果忘记了。此外,编译器(甚至是PC-lint以我吃惊)将不会给出任何提示/问题,如果LOOP_COUNT不小心设置为一个值大于255的> 8位平台,但会在8位平台生成警告,这将减少可移植性和引入错误,但是可以使用避免#如果检查。


  2. 使用至少数据类型尽可能如果存储器使用是像在数组或结构的关注。例如:

      uint_least8_t阵列[100];

    这是,如果内存使用率是关注的声明数组最便携和有效的方式。这种类型会给一个字节数组,如果字节访问是可能的平台上,并以其他方式提供最小的访问宽度整型数组。此外,至少类型可以在结构中被使用,如果我们有结构的阵列。

    型最少也能遭遇的问题,快的类型做了变量宽度可以在不同的平台来改变这两种情况下。


  3. 避免固定宽度的数据类型尽可能因为它们可能甚至不某些平台上存在,除了硬件寄存器的访问,通信协议映射,等等,我们需要知道变量的确切位。例如:

      typedef结构{
        uint8_t有标志;
        uint8_t有长度;
        uint8_t有数据[100];
        uint16_t CRC;
    } __attribute __((包装))package_t;

    通常 __属性__((包装))(或类似的东西)应单独使用,以确保没有空白将被插入对于这些情况,因为这可能是一个问题


现在,如果我的理解是真实的,我认为至少数据类型是更可能在阵列或结构被使用,快速数据类型是更可能被用于单变量和固定数据类型可能不会在顺序使用以达到最大的可移植性和效率。但输入快和至少是每一次并不令人鼓舞。所以,我认为一种集如下:

 的typedef [U] intN_t OS_ [U | S] exactN_t;
    的typedef [U] int_fastN_t OS_ [U | S] N_t;
    / *我不能想出一个更好的名字* /
    的typedef [U] int_leastN_t OS_ [U | S] minN_t;
    / *这些可能改变* /
    的typedef uint_least8_t os_byte_t;
    的typedef uint_least16_t os_word_t;
    / * ... * /


  • 第一,重要的问题是,我的理解是真的吗?

  • 什么是使用C99标准型最轻便和有效的方式,你会如何声明它们,如果它是不是真的?

  • 我的类型集有意义或者是可能产生马车code?

另外,我会很高兴地知道如何以及在何处使用C99标准类型。


解决方案

编写高度便携code是困难的。写作高度便携code,它是最佳的,正常工作就更难了。

对于大多数的时候,如果它是可行的,我会建议使用基本类型,如 INT 字符等,而不是 uint8_t有 uint8_fast_t 。类型 INT 字符保证存在。毫无疑问。当然,有时我们需要从code特定的行为,这将需要一个特定类型的 - 但code将最有可能突破,如果系统不支持类型完全相同。

有关您的第一个例子,这是极不可能的,你会比使用得到更好的性能 INT ,除非你的code的设计(也)上运行8位处理器。在一个16位,32位或64位处理器,原生规模将是最快的for循环(无符号正对64位机器上稍微好一点,因为它不需要符号扩展)。

在你的第二个例子,如果数组足够大,以保证在使用任何字符 INT <节省空间,它真的只在乎/ code>或或任何有意义的内容。在现代机器(包括许多嵌入式平台,甚至usign堆栈时),400字节是不是真的那么多。

有关你的第三个例子,很明显,对于协议,您将需要使用协议定义完全匹配类型,或事物会出问题。在不支持的正确类型的平台,这将在某些特定于平台的方式来解决 - 你如何去了解这将取决于到底是什么平台实际上支持。

因此​​,要回答你的具体问题:


  • 好像你了解整个概念。但你似乎也
    试图比它需要被推向进一步推动它,如果
    说得通。

  • 不适用。

  • 过度使用特殊类型的变量可能:


    1. 慢下来的东西,

    2. 可能导致错误,尤其是如果它不能持续使用。


还记住性能往往是的90%的时间采取的是code的10%的情况。理解在哪里(在正常使用),您的code花费它的时间是至关重要的。当然,移植code到不同的系统和不同的架构时,您可能会发现性能瓶颈动作的基础上,处理器速度,缓存大小和内存速度之间的关系。具有较高的处理器速度,但(realtively)小型高速缓存系统可以比更低的时钟速度和更大的缓存类似的系统有时会表现差,就像一个例子。

First, here is what I understand and think what is true for the question.

  1. Use fast data types for single variables like counters or for loop indexes. For example:

    #define LOOP_COUNT (100U)
    
    uint_fast8_t index;
    for(index = 0; index < LOOP_COUNT; index++){
        /* Do something */
    }
    

    I suppose the most suitable type in here is uint_fast8_t since index can never exceed 255 and this will be the fastest implementation for all platforms. If I used unsigned int instead, it will be fastest in >=16 bits platforms but will be slower in <16 bits platforms as int is 16 bits minimum by standard. Also, if I used uint8_t it will be slower on >8 bits platforms as the compiler adds an AND 0xFF instruction to check overflow for each increment (my ARM7 compiler does that even on full speed optimization). size_t is also not an option since it can be bigger than the native integer size.

    Bad side (?) of this if an overflow is expected for 8 bits, it is not gonna happen. Programmer should check for overflow manually (as he/she should IMHO), which may result in buggy code if forgotten. Also, compiler (and even PC-Lint to my surprise) will not give any warning/issue if LOOP_COUNT "accidentally" set to a value bigger than 255 on >8 bits platforms, but the warning will be generated on an 8 bits platform, which will reduce portability and introduce bugs, but this can be avoided with #if checks.

  2. Use least data types as much as possible if memory usage is of concern like in arrays or structures. For example:

    uint_least8_t array[100];
    

    It is the most portable and efficient way to declare arrays if memory usage is of concern. This type will give a byte array if byte access is possible on the platform, and give the smallest accessible width integer array otherwise. Also, least types can be used in structures if we have arrays of the structure.

    Least type can also suffer the problems fast types do, as width of variables can be changed on different platforms for both cases.

  3. Avoid fixed width data types as much as possible as they may not even exist on some platforms, except hardware register access, communication protocol mapping, etc. where we need to know the exact bits of the variable. For example:

    typedef struct {
        uint8_t  flags;
        uint8_t  length;
        uint8_t  data[100];
        uint16_t crc;
    } __attribute__((packed)) package_t;
    

    Usually __attribute__((packed)) (or something similar) should be used to ensure no padding will be inserted for these cases, as this can be a problem by itself.

Now, if my understanding is true, I think least data types are more likely to be used in arrays or structures, fast data types are more likely to be used for single variables and fixed data types are unlikely to be used in order to achieve maximum portability and efficiency. But typing "fast" and "least" every time is not encouraging. So, I think of a type set as follows:

    typedef [u]intN_t       os_[u|s]exactN_t;
    typedef [u]int_fastN_t  os_[u|s]N_t;
    /* I couldn't come up with a better name */
    typedef [u]int_leastN_t os_[u|s]minN_t;
    /* These may change */
    typedef uint_least8_t   os_byte_t;
    typedef uint_least16_t  os_word_t;
    /* ... */

  • First and the important question is, is my understanding true?
  • What would be the most portable AND efficient way to use C99 standard types and how would you declare them if it is not true?
  • Does my type set makes sense or is it likely to produce buggy code?

Also, I would be pleased to know how and where you use C99 standard types.

解决方案

Writing highly portable code is hard. Writing highly portable code that is optimal and works correctly is even harder.

For the majority of time, if it is feasible, I would suggest using basic types such as int, char, etc, rather than uint8_t or uint8_fast_t. The types int and char is guaranteed to exist. There is no doubt about that. Of course, SOMETIMES we need a specific behaviour from the code, and that will require a specific type - but that code will most likely break if the system doesn't support that exact type.

For your first example, it is extremely unlikely that you'll get better performance than using int, unless your code is designed to (also) run on 8-bit processors. On a 16-, 32- or 64-bit processor, the native size will be the fastest for loops (unsigned being slightly better on 64-bit machines, since it doesn't require sign extension).

In your second example, it really only matters if the array is large enough to warrant the space-saving over using either char or int or short or whatever makes sense for the content. On modern machines (including many embedded platforms and even when usign the stack) 400 bytes isn't really that much.

For your third example, obviously, for protocols, you will need to use types that match the protocol definition exactly, or things will go wrong. On platforms that doesn't support the correct type, this will have to be solved in some platform specific way - how you go about it will depend on exactly what the platform actually supports.

So, to answer your concrete questions:

  • Seems like you understand the overall concept. But you also seem to be trying to push it further than it needs to be pushed, if that makes sense.
  • Not applicable.
  • Excessive use of "special type" variables is likely to:

    1. slow things down,
    2. potentially cause bugs, especially if it's not used consistently.

Remember also that performance is often a case of 90% of the time is taken by 10% of the code. Understanding where (under normal usage) your code spends its time is critical. Of course, when porting code to different systems and on different architectures, you may find that the performance bottleneck moves, based on the relationship between processor speed, size of caches and memory speed. A system with high processor speed, but (realtively) small caches can sometimes perform worse than a similar system with lower clock-speed and bigger caches, just as one example.

这篇关于如何使用C99标准型跨大多数平台最大的可移植性和效率?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆