Skip to content

C - 类型陷阱

陷阱

  • 有如下这段代码:

    typedef struct length_type_data_t {
        uint8_t length;
        uint8_t type;
        uint8_t data[0];
    } __attribute__((packed)) length_type_data_t;
    
    int main() 
    {
      int len = 0; 
      printf("diff: %ld\n", len - sizeof(length_type_data_t));
    
      for(int pos = 0; pos < ( len - sizeof(length_type_data_t) ) ;){
            printf("Enter loop!\n");
            break;
      }
      return 0;
    }
    

  • ::: warning 问题

在上面这段代码中,打印了diff: -2, 那么请问是否会进入for循环,打印Enter loop!呢?

:::

  • 答案是**会**进入for循环。而我们预期的运行结果是不进入for循环,即便我们把pos的类型改成了uint32_t类型,也还是会进入for循环。

  • 证明了编译器把( len - sizeof(length_type_data_t) )隐式转换成了Unsigned类型,导致最后的值不是-2.

  • 解决办法有如下两种:

  • 方法1:
    int main() 
    {
      int len = 0; 
      printf("diff: %ld\n", len - sizeof(length_type_data_t));
    
      for(int pos = 0; pos < ( len - (int)sizeof(length_type_data_t) ) ;){
            printf("Enter loop!\n");
            break;
      }
      return 0;
    }
    /* 不进入for循环 */
    
  • 方法2:
    int main() 
    {
      int len = 0; 
      printf("diff: %ld\n", len - sizeof(length_type_data_t));
      int diff = len - sizeof(length_type_data_t);
      for(int pos = 0; pos < diff;){
            printf("Enter loop!\n");
            break;
      }
      return 0;
    }
    /* 不进入for循环 */
    
  • 推荐用第二种方法,不要在for里面计算复杂的表达式。

扩展

  • 如果有如下代码如下所示。是否还会进入for循环呢?
    int main() 
    {
      int diff = -2;
      for(uint32_t pos = 0; pos < diff;){
            printf("Enter loop!\n");
            break;
      }
      return 0;
    }
    

总结

  • 一定要小心类型的隐式转换和溢出的问题。
  • for循环中的大小比较的类型一定要是相同的,不一样的类型会造成预想不到的后果。