Unnecessary padding

Члены struct дополнены, чтобы выполнить требование выравнивания, когда реорганизация членов, чтобы выполнить это требование сохраняет память

Описание

Это средство проверки отмечает struct возразите, где расположение его членов требует дополнительного дополнения, чтобы выполнить требование выравнивания. Реорганизация членов такого struct объектная сила выполняет требование выравнивания, не требуя никакого дополнительного дополнения. Поскольку дополнение является ненужным в целях выравнивания, устранение дополнения сохраняет память. Рассмотрите этот struct в системе на 64 бита:

 struct A {
      uint32_t m1;// 4 bytes
      uint64_t m2;// 8 bytes
      uint32_t m3;// 4 bytes
  }; 
 
Чтобы максимизировать скорость, C/C++ требует, чтобы переменная была считана в одном цикле, если это возможно. В этой системе 8 байтов могут быть считаны во время одного цикла. Если m1 и m2 помещаются последовательно, машина требует, чтобы два цикла считали m2. Вместо этого переменная m1 помещается в 8-байтовый паз отдельно после дополнения его на 4 байта. Затем m2 помещается в его собственный 8-байтовый паз. Переменная m3 также дополнен, чтобы выполнить требование выравнивания для struct A. Из-за дополнения, размера A 24 байта даже при том, что объединенный размер m1, m2, и m3 16.

Polyspace® повышения этот дефект, когда требование выравнивания может быть выполнено путем реорганизации членов struct. Например, перестраивая члены A может устранить дополнение:

 struct A {
      uint64_t m2;// 8 bytes
      uint32_t m1;// 4 bytes
      uint32_t m3;// 4 bytes
  }; 
 
Здесь, m2 занимает первое место в 8-байтовом пазе. Затем m1 и m3 помещаются вместе в другом 8-байтовом пазе. Эта перестановка устраняет дополнение.

Риск

Ненужное дополнение тратит впустую память, которая может иметь несколько неблагоприятных ударов:

  • Используя большую память, чем необходимая сила исчерпывают доступную память, приводящую к отказу разбивки на страницы.

  • Функционирует, такие как memcpy и memcmp может занять больше времени.

Исправление

Чтобы зафиксировать этот дефект, перестройте члены struct устранить ненужное дополнение. Объявите самый большой struct члены сначала, и затем сохраняют объявления того же самого - измеренные члены вместе. Вы можете также использовать pragma директивы, чтобы устранить дополнение.

Повышения производительности могут варьироваться на основе компилятора, реализации библиотеки и среды, которую вы используете.

Примеры

развернуть все

#include <stdint.h>
struct GlobalStructA { //Noncompliant         
    uint32_t m1;                
    uint64_t m2;
    uint32_t m3;                
};

// Using pragma pack to eliminate padding
//
#pragma pack(push, 1)
struct GlobalStructPragmaPack {//Compliant           
    uint8_t  m1;
    uint64_t m2;
    uint8_t  m3;
};
#pragma pack(pop)
struct Array //Noncompliant                  
{
    uint8_t  m1[5];
    uint64_t m2;
    uint8_t  m3[3];
};
struct StructWithBitField //Noncompliant   
{
    uint8_t  m1 : 1;
    uint8_t     : 1;
    uint8_t     : 1;
    uint8_t  m2 : 1;

    uint64_t m3;

    uint8_t  m4 : 1;
    uint8_t     : 1;
    uint8_t     : 1;
    uint8_t  m5 : 1;
};

В этом примере Polyspace отмечает стиль C struct объекты, которые содержат ненужное дополнение. Polyspace принимает, что процессор имеет 32-битный размер слова по умолчанию. Используйте опцию -target x86_64 запускать этот пример.

  • Поскольку 32-битная переменная m1 объявляется сначала в GlobalStructA объект, это дополнено к 64 битам. Polyspace отмечает объект, потому что дополнение может быть устранено путем объявления m1 после m2.

  • Объект GlobalStructPragmaPack имеет подобную проблему с порядком ее объявления элемента, но дополнение устраняется pragma директива. Polyspace не отмечает этот объект.

  • В объекте Array, потому что m1[5] объявляется перед m2, 40-битный массив дополнен к 64 битам. 24-битный массив m3 дополнен к 64 битам. Эти дополнения могут быть устранены путем объявления m2 сначала. Поскольку Array содержит ненужное дополнение, Polyspace отмечает объект.

  • В объекте StructWithBitField, существует два битовых поля, каждый состоящий из 4 битов. Поскольку m3 объявляется между этими двумя битовыми полями, они дополнены. Polyspace отмечает объект.

Коррекция

Чтобы зафиксировать этот дефект, измените порядок объявления устранить дополнение. Например:

  

#include <stdint.h>
struct GlobalStructA { //Compliant         
	uint64_t m2;
	uint32_t m1;                
	uint32_t m3;                
};

// Using pragma pack to eliminate padding
//
#pragma pack(push, 1)
struct GlobalStructPragmaPack {//Compliant           
	uint64_t m2;
	uint8_t  m1;
	uint8_t  m3;
};
#pragma pack(pop)
struct Array //Compliant                  
{
	uint64_t m2;
	uint8_t  m1[5];
	uint8_t  m3[3];
};
struct StructWithBitField //Compliant   
{
	uint64_t m3;
	
	uint8_t  m1 : 1;
	uint8_t     : 1;
	uint8_t     : 1;
	uint8_t  m2 : 1;

	uint8_t  m4 : 1;
	uint8_t     : 1;
	uint8_t     : 1;
	uint8_t  m5 : 1;
};
#include <string>
#include<stdint.h>
class GlobalClassWithString {//Noncompliant
    uint32_t    m1;
    std::string m2;
    uint32_t    m3;
};
class GlobalClassC {//Noncompliant
  public:
    uint32_t m1;
  protected:
    uint64_t m2;
  private:
    uint32_t m3;
};

Polyspace принимает, что процессор имеет 32-битный размер слова по умолчанию. Используйте опцию -target x86_64 запускать этот пример. Из-за порядка, в котором объявляются члены предыдущих классов, классы содержат ненужное дополнение. Polyspace отмечает эти классы. public, private, или protected марки членов не влияют, как они организованы в памяти.

Коррекция

Чтобы зафиксировать этот дефект, измените порядок объявления устранить дополнение. Например:

#include <string>
#include<stdint.h>
class GlobalClassWithString{//Compliant
    std::string m2;
	uint32_t    m1;
    uint32_t    m3;
};
class GlobalClassC {//Compliant
  protected:
    uint64_t m2;  
  public:
    uint32_t m1;
  private:
    uint32_t m3;
};
#include <stdint.h>
struct SmallPadding {     //Noncompliant in 16-bit, compliant in 32-bit
    uint8_t m1;
    uint8_t m2;
    uint8_t m3;
    uint8_t m4;
    uint8_t m5;
    uint8_t m6;
    uint8_t m7;
    uint32_t m8;
    uint8_t m9;
    uint8_t m10;
    uint8_t m11;
    uint8_t m12;
    uint8_t m13;
    uint8_t m14;
    uint8_t m15;
};

Этот пример показывает чувствительность этого средства проверки к размеру слова процессора. В объекте SmallPadding, существует 16 битов дополнения, которое мало по сравнению с общим размером struct. Когда размер слова процессора будет большим, маленькое дополнение вряд ли вызовет неэффективность. Например, чтение SmallPadding требует трех циклов независимо от дополнения, если процессор имеет 64-битное выравнивание. Polyspace не отмечает объект в этом случае. Когда размер слова процессора меньше, дополнение может привести к неэффективности. Например, если выравнивание процессора составляет 16 битов, добавленное дополнение может вызвать неэффективность в чтении объекта. Polyspace отмечает SmallPadding в этом случае. Чтобы установить выравнивание процессора к 16 битам в анализе Polyspace, используйте опции -target mcpu -align 16. См. Типовые целевые опции.

Информация о результате

Группа: Производительность
Язык: C | C++
Значение по умолчанию: Off
Синтаксис командной строки: UNNECESSARY_STRUCT_PADDING
Удар: Средняя
Введенный в R2021b