Как избавиться от "dereferencing ... will break strict-aliasing rules" варнингов в библиотеке UIPEthernet?

сейчас попробовал - у меня и на Дуе сегодня предупреждений НЕТ! А вчера были.

Поскольку в чудеса я не верю, а библиотека, судя по Гитхабу, со вчерашнего дня не менялась - остается предположить, что дело в том, что вчера и сегодня я пробовал на разных ПК.
Видимо в разных версиях ИДЕ 1.х где-то эти предупрежления включены, а где-то выключены.

Так что прошу прощения, если у кого-то мои опыты не воспроизведутся.

Я пытался сказать, что флаг вот этот -Wstrict-aliasing - его в здравом уме люди не используют, в обычном коде.

Зачем его ардуино-тим включила - загадка, но наверно у них там были причины.

Поэтому, на твоем месте, я бы просто забил. Но если заказчику прям неймется, то, как обычно :):

#pragma GCC diagnostic ignored "-Wstrict-aliasing"
Код с варнингом
#pragma GCC diagnostic warning "-Wstrict-aliasing"                

По поводу выравнивания: GCC в любом случае выравнивает все переменные, хоть на стеке, хоть глобальные, вне зависимости от их размера. (Говорим про 32бит)

Так что налететь на не выровненное обращение… Ни разу не случалось у меня. Не припомню, по крайней мере. Там же компилятор еще не выровненный аксесс будет пытаться выровнять - по байтам читать, например. Ну, по крайней мере, когда мне было это интересно, я смотрел что генерирует GCC для Freescale MPC866 - и удивлялся.

Так, почитав статью, на которую вышел благодаря @ЕвгенийП , родил такое чудо:


struct ttt {
  uint32_t a;
  uint8_t b;
  uint16_t c;

};

char buffer[333];

struct ttt* bb(char* c) {
  static struct ttt p;
  memcpy(&p, c, sizeof(struct ttt));
  return &p;
}

#define BUF ((struct ttt *) &buffer[12])     // <<<<<< warning produced here
#define BUF_FIX ((struct ttt *)bb(&buffer[12]))  // <<<<< no warning here

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.print(BUF->a);
  Serial.print(BUF_FIX->a);
}

BUF - оригинальный макрос, который дает предупреждение, BUF_FIX - исправленный. Чтобы убрать варнинг, пришлось, в соответствии с рекомендациями статьи, написать промежуточную функцию bb() c memcpy внутри. Выглядит, конечно, переусложненно, но предупреждение ушло.
Дядя в статье утверждает, что современные оптимизаторы распознают такое использование memcpy и уменьшают оверхед от его использования

Вопрос к гуру - что скажете? Или я где-то накосячил и стало еще хуже?

Изменено, стилистические правки

Я делал разбиение флоатов, лонгов и тп на байты через void *
Тогда не ругается.

И добавка к коду в #43 .
Поскольку в библиотеке UIPEthernet подобных макросов несколько под разные структуры, то чтобы не писать под каждый свою версию функции bb(), лучше оформить ее шаблоном:

template<class T>
T* bb(char* c) {
  static T p;
  memcpy(&p, c, sizeof(T));
  return &p;
}

можно тут и кое-какую оптимизацию сделать…
Но это позже, когда мне “старшие” скажут. чушь я написал или нет

Проблема закопалась - один буфер. Адрес один и тот-же. Последовательные вызовы функции bb() будут затирать данные от прошлых вызовов.

да и фиг с ними, это же временный экзепляр структуры.

Или Вы имеете в виду, что все экзепляры шаблона

template<class T>
T* bb(char* c) {

будут иметь общий буфер?

Добавка - да нет, не будут, у них же даже тип разный

Про шаблоны - не знаю. Я вот что имею ввиду:

(компилируется Cygwin/Mingw)

Простая функция, которая возвращает указатель на строчку:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int bool;
#define true ((bool)1)
#define false ((bool)0)

#include <sys/unistd.h>
#include <sys/stat.h>
#include <dirent.h>



// Байты в Килобайты: 
// Вход: размер, в байтах
// Выход: возвращает указатель на строчку с количеством килобайт
//
static char *b2kb_bad(unsigned int size) {

  static char bufs[16] = { 0 };
  sprintf(bufs,"%6.1f",(float)size / 1024.0f);
  return bufs;
}



// То же самое, что и выше, но есть нюанс.
static char *b2kb(unsigned int size) {

  static unsigned char idx = 0;
  static char bufs[16][12] = { 0 };
  char *p = &(bufs[idx++][0]);
  sprintf(p,"%6.1f",(float)size / 1024.0f);
  idx &= 15;
  return p;
}




int main() {


  printf("Testing b2kb() : %sKb %sKb %sKb %sKb\r\n",b2kb(1000*1024),b2kb(1000*1024*1024),b2kb(10*1024),b2kb(666*1024));

  printf("Testing b2kb_bad() : %sKb %sKb %sKb %sKb\r\n",b2kb_bad(1000*1024),b2kb_bad(1000*1024*1024),b2kb_bad(10*1024),b2kb(666*1024));

  return 0;
};

Вывод на экран будет такой:

Да, я понял, спасибо.

Если же без шуток, то правильным решением будет выключить оптимизацию, которая основана на strict aliasing rules. Это будет правильнее, чем пытаться заткнуть компилятор атрибутом may_alias или #pragma GCC diagnostic.

-fno-strict-aliasing - то, что вам поможет. Это идейно правильное решение - мы не пытаемся обмануть компилятор. Тут уже никакого undefined behaviour не предвидится.

Так уже, вроде, обсуждали, что “разбиение” и “собирание” - процессы не симметричные.

Та далеко я не читал. Сейчас посмотрю.

хм…
Расстроили вы меня своим примером затирания буфера последовательными вызовами.
Тем более что в библиотеке все еще хуже - они там не только читают область памяти через указатель на структуру, но еще и пишут туда:

 BUF->flags = TCP_RST | TCP_ACK;

что, конечно же, не будет сохраняться во временной структуре.
Можно, конечно, дополнить функцию, чтобы не перезатирать структуру, если адрес не изменился:

template<class T>
T* bb(char* c) {
  static char* old_ptr = NULL;
  static T p;
  if ( c != old_ptr) {
      memcpy(&p, c, sizeof(T));
      old_ptr = c;
  }
  return &p;
}

но это все равно хождение по тонкому льду…

Евгений, чтобы Вас зря не дергать - еще сразу прочитайте #41. Как выяснилось, наличие предупреждений зависит от версии Ардуино ИДЕ. Например, в 1.8.19 предупреждений в примере AdvancedChatServer.ino для платы Дуе нет.
В какой версии я эти предупреждения видел вчера, смогу сказать только в понедельник.

Вы знаете, наверное, я что-то не так делаю, или у Вас какие-то не те опции или не те ядра (у меня всё из коробки).

Вот, смотрите

Вот

Сообщение компилятора
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master/utility/mempool_conf.h:5:0,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master/utility/mempool.h:28,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master/utility/Enc28J60Network.h:28,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master/UIPEthernet.h:35,
                 from D:\GoogleD\Soft\Kaka\AdvancedChatServer\AdvancedChatServer.ino:43:
d:\GoogleD\Soft\libraries\UIPEthernet-master/utility/uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master/UIPClient.h:37:0,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master/UIPEthernet.h:41,
                 from D:\GoogleD\Soft\Kaka\AdvancedChatServer\AdvancedChatServer.ino:43:
d:\GoogleD\Soft\libraries\UIPEthernet-master/utility/logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\Dhcp.cpp:6:0:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\Dhcp.cpp:17:0:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/mempool_conf.h:5:0,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/mempool.h:28,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/Enc28J60Network.h:28,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPEthernet.h:35,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPUdp.cpp:20:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPClient.h:37:0,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPEthernet.h:41,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPUdp.cpp:20:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\Dns.cpp:5:0:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\Dns.cpp:24:0:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/mempool_conf.h:5:0,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/mempool.h:28,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/Enc28J60Network.h:28,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPEthernet.h:35,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPEthernet.cpp:27:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPClient.h:37:0,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPEthernet.h:41,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPEthernet.cpp:27:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPClient.cpp:19:0:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPClient.cpp:23:0:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPClient.cpp: In static member function 'static uint16_t UIPClient::_write(uip_userdata_t*, const uint8_t*, size_t)':
d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPClient.cpp:262:1: warning: label 'ready' defined but not used [-Wunused-label]
 ready:
 ^~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/mempool_conf.h:5:0,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/mempool.h:28,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/Enc28J60Network.h:28,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPEthernet.h:35,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPServer.cpp:19:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPClient.h:37:0,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPEthernet.h:41,
                 from d:\GoogleD\Soft\libraries\UIPEthernet-master\UIPServer.cpp:19:
d:\GoogleD\Soft\libraries\UIPEthernet-master\utility/logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\mempool_conf.h:5:0,
                 from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\mempool.h:28,
                 from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\mempool.cpp:20:
D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\mempool.cpp:22:0:
D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uip.h:56:0,
                 from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uip_arp.h:62,
                 from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uip_arp.c:61:
D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\mempool_conf.h:5:0,
                 from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\mempool.h:28,
                 from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\Enc28J60Network.h:28,
                 from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\Enc28J60Network.cpp:25:
D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
In file included from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\Enc28J60Network.cpp:34:0:
D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\logging.h:24:2: warning: #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage." [-Wcpp]
 #warning "You can configure LogObject and ACTLOGLEVEL in 'utility/logging.h'. More verbosity more memory usage."
  ^~~~~~~
In file included from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uip.h:56:0,
                 from D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uip.c:82:
D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uipopt.h:97:4: warning: #warning "Endianness configured automaticaly." [-Wcpp]
   #warning "Endianness configured automaticaly."
    ^~~~~~~
D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uip.c: In function 'uip_process':
D:\GoogleD\Soft\libraries\UIPEthernet-master\utility\uip.c:857:39: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
   if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) {
                                       ^~
Скетч использует 17976 байт (7%) памяти устройства. Всего доступно 253952 байт.
Глобальные переменные используют 1098 байт (13%) динамической памяти, оставляя 7094 байт для локальных переменных. Максимум: 8192 байт.

Ардуино Дуе

Для Меги предупреждений и у меня нет.

(не обижайтесь, но это написано и в первом сообщении, и в 25)

Блин! ну, чё ж так-то …

:frowning:

Да. похоже мой метод из #43, 45 даже с доработкой из #54 не годится.

Поскольку авторы библиотеки не только читают буфер через указатель на структуру, но и пишут в него - они это явно делают не просто так. Пока в библиотеке не нашел, но скорее всего они потом отправляют измененный пакет в сеть из этого же буфера. А это, конечно, с моей временной структурой работать не будет.

Посмотрел. Действительно библиотека написана в парадигме “плеванто на строгий алиасинг”, поэтому, без её переделки никакие методы не годятся.

Так что, ответ на вопрос

представляется таким:

  1. либо не пользоваться этой библиотекой
  2. либо выключить нахрен это предупреждение опцией -Wno-strict-aliasing

Нет, если поднапрячься, то можно найти способ как обмануть, только зачем? Библиотека всё равно будет рыться в памяти как в своём кармане, потому вопрос доверяете Вы ей или нет. Доверяете – отключайте предупреждение. Не доверяете – не пользуйтесь.

Как-то так.

1 лайк

ну да, нынешний распорядитель репо библиотеки тоже это посоветовал: