在嵌入式MCU应用中,最好在for循环中使用uint_fast16_t或size_t吗?

时间:2018-02-22 09:30:08

标签: c optimization embedded c99 stdint

我想为可在不同MCU(16位,32位或64位基础)上运行的应用程序编写可移植代码。

  • MSP-430
  • nRF52(32位)
  • PIC(16位)
  • C51(8位)

让我们考虑一下这个片段:

events = 0;
for (size_t i = 0; i < sizeof(array) / sizeof(array[0]); i++) {
    if (array[i] > threshold) 
        events++;
}

我的问题涉及循环计数器变量的类型,这里是size_t

通常size_t应该足够大以解决我系统的所有内存问题。因此,使用size_t可能会影响我的代码在某些体系结构上的性能,因为此变量的宽度对于我拥有的数组的长度来说太大了。

有了这个假设,我最好使用uint_fast16_t因为我知道我的array少于65k元素。

关心这篇文章是否有意义,或者我的编译器是否足够聪明以优化它?

我认为与uint_fast16_t相比,size_t很少使用,而且很少使用。{/ p>

更具体地说明我的问题:

我是否通过系统地为我的循环计数器(uint_fast8_tuint_fast16_t,...)使用正确的类型来改进代码的可移植性,或者我更喜欢使用size_t,因为在在大多数情况下,它在性能方面没有差异吗?

修改

根据您的评论和评论,很明显,大多数情况下,编译器将注册循环计数器,因此在size_tuint_fast8_t之间进行选择并不重要。

https://godbolt.org/g/pbPCrf

main: # @main
  mov rax, -80
  mov ecx, dword ptr [rip + threshold]
.LBB0_1: # =>This Inner Loop Header: Depth=1
  [....]
.LBB0_5: # in Loop: Header=BB0_1 Depth=1
  add rax, 8     # <----------- Kept in a register
  jne .LBB0_1
  jmp .LBB0_6
.LBB0_2: # in Loop: Header=BB0_1 Depth=1
  [....]
.LBB0_6:
  xor eax, eax
  ret

如果循环长度变得大于内部CPU寄存器,则该问题可能成为一个真正的问题。在8位微控制器上进行512次循环。

3 个答案:

答案 0 :(得分:1)

对于便携式代码,请使用size_t

对于快速代码......好吧,这取决于你的编译器和处理器。如果使用16位类型,它可能在16位处理器上运行得最快,但在64位处理器上实际上而不是size_t。在衡量绩效之前,你不应该做任何事情。

我使用size_t并且只有在存在可解决的性能问题时才会进一步考虑进行优化。

答案 1 :(得分:0)

与任何优化一样,首先为便携式常见案例编写简单代码(使用size_t)。然后使用其他类型查看平台上的程序集。 如果其中一种类型的工作速度更快或生成的代码明显更少,您可以为这些类型的访问键入一种特殊的索引类型。例如,您可以使用near,far和huge指针(以及相应的索引)的概念,除非使用固定宽度类型,否则为清晰起见。

/* The compiler for my16bitmcu, cannot detect ranges to use appropriate types */
#if defined __MY16BITMCU__ /* replace with architecture's predefined macro */
  typedef uint16_t size8t, size16t; /* use uint8_t for size8t on 8bit */
  typedef uint32_t size32t;
  typedef uint64_t size64t;
  typedef int16_t ptrdiff8t, ptrdiff16t; /* use int8_t for ptrdiff8t on 8bit */
  typedef int32_t ptrdiff32t;
  typedef int64_t ptrdiff64t;
#else
  typedef size_t size8t, size16t, size32t, size64t;
  typedef ptrdiff_t ptrdiff8t, ptrdiff16t, ptrdiff32t, ptrdiff64t;
#endif

/** example usage: sum the total of an array
 ** using size8t for count reduces complexity on some 8/16 bit systems
 ** on other systems, size8t is the same as size_t
 **/
int sum_numbers(int *numbers, size8t count){
  int total = 0;
  while(count--) total += numbers[count];
  return total;
}

答案 2 :(得分:-1)

对于MCU,请使用您知道适合阵列大小的最小类型。如果您知道该数组可能大于256字节但从不大于65536,那么function sendMail($applicationID){ $host = 'localhost'; $user = 'username'; $pass = 'password'; $db = 'database'; $conn = mysqli_connect($host,$user,$pass,$db) or die("Error ". mysqli_connect_error()). PHP_EOL; $distributor_details = mysqli_fetch_assoc(mysqli_query($conn,"select * from distributor where status = '1' and deleted IS NULL and id = '$applicationID' limit 0,1 ")); if(isset($distributor_details['id'])){ $state=mysqli_fetch_array(mysqli_query($conn,"select * from tbl_state where id='".$distributor_details['state']."' ")); $country=mysqli_fetch_array(mysqli_query($conn,"select * from tbl_country where id='".$distributor_details['country']."' ")); /*<tr> <th height="25">Application ID:</th><td>'.distributorNumber($distributor_details['id']).'</td> </tr>*/ $message = '<html> <head> <title>Triveni Almirah</title> </head> <body> <h1>Dealer/Distributor Enquiry Details</h1> <table cellspacing="0" style="border: 2px dashed #3c8dbc; width: 100%; height: auto;"> <tr style="background-color: #e0e0e0;"> <th height="25">Name:</th><td>'.stripslashes(strtoupper($distributor_details['fname'])).'</td> </tr> <tr> <th height="25">Email Id:</th><td>'.$distributor_details['email'].'</td> </tr> <tr style="background-color: #e0e0e0;"> <th height="25">Mobile:</th><td>'.$distributor_details['mobile'].'</td> </tr> <tr> <th>Address:</th><td>'.strtoupper($distributor_details['city']).'</td> </tr> <tr> <th height="25">Comments:</th><td>'.$distributor_details['comment'].'</td> </tr> <tr style="background-color: #e0e0e0;"> <th height="25">Posted Date:</th><td>'.date("d-m-Y",strtotime($distributor_details['post_date'])).'</td> </tr> </table> </body> </html>'; $headers = "MIME-Version: 1.0;\n"; $headers .= "Content-type: text/html; charset=iso-8859-1;\n"; $headers.='From:HIRDESH - VASHISHTHA <noreply@domain.com>' . "\r\n".PHP_EOL; //$headers.='CC: abcd48@gmail.com' . "\r\n".PHP_EOL; //$port = 587; //$auth = true; //echo $message; die; mail("data@domain.com","Distributorship Enquiry",$message,$headers); } return true; }确实是最合适的类型。

这里的主要问题是具有扩展闪存(> 64kb)的16位MCU,提供24或32位地址宽度。这是许多16苦的常态。在这样的系统上,uint_fast16_t将是32位,因此将是一种慢速类型。

如果不考虑8或16位苦味的可移植性,那么我会使用size_t

根据我的经验,许多嵌入式编译器不够智能,无法优化代码使用比上述类型更小的类型,即使它们可以在编译时减去数组大小。