Увидел сегодня очень показательный пример того, как ChatGPT «пишет» программы. В общем, очередной раз читаю курс по программированию всяких встраиваемых устройств, и ближе к концу семестра, осознав весь зашитый в формулу для оценок фашизм, нарисовалась студентка с желанием сдать все и сразу, включая задания, по которым дедлайн уже прошел. Решил посмотреть код — и заподозрил неладное. Но сначала — давайте я покажу его вам в слегка сокращенном виде, найдете ли вы здесь какие-то ошибки?
#include <stdio.h>
#include "periph/i2c.h"
#include "periph/gpio.h"
#include "periph_conf.h"
#include "bme280.h"
int main(void)
{
/* Инициализация датчика BME280 */
bme280_t bme280_dev;
int bme280_res = bme280_init(&bme280_dev, I2C_DEV(0), BME280_I2C_ADDRESS);
if (bme280_res != 0) {
printf("Ошибка инициализации BME280: %d\n", bme280_res);
return 1;
}
/* Получение и вывод показаний датчиков */
while (1) {
/* Получение показаний BME280 */
bme280_measure(&bme280_dev);
float bme280_temperature = bme280_temp_comp_2(&bme280_dev, bme280_dev.temperature);
float bme280_humidity = bme280_humid_comp(&bme280_dev, bme280_dev.humidity);
float bme280_pressure = bme280_pres_comp(&bme280_dev, bme280_dev.pressure);
printf("BME280: температура=%.1f°C, влажность=%.1f%%, давление=%.1f мбар\n",
(double)bme280_temperature, (double)bme280_humidity, (double)bme280_pressure);
}
xtimer_sleep(5);
}
return 0;
}
Меня сразу смутил используемый для работы с датчиком (банальный BME280) API — он очень отдаленно напоминал реализованный в Riot OS, не говоря уж о библиотеке для Arduino или ARM mbed, или о «фирменном» бошевском драйвере. Но еще больше удивил соседний файл (с кодом, который якобы написан той же самой студенткой!), где работа с датчиком выглядела примерно так (опять же, в максимально сокращенном виде):
#include "xtimer.h"
#include "bme280.h"
#define BME280_DEV I2C_DEV(0)
static bme280_t dev_bme280;
int main(void)
{
int8_t res;
res = bme280_init(&dev_bme280, BME280_DEV);
if (res != BME280_OK) {
puts("Could not initialize BME280 sensor");
return 1;
}
while (1) {
float temperature_bme280;
bme280_read_temperature(&dev_bme280, &temperature_bme280);
printf("BME280 temperature: %0.1f C\n", temperature_bme280);
xtimer_sleep(5);
}
return 0;
}
Видите что-то общее? Вот и я не вижу. При этом в принципе оба варианта API мне представляются вполне обоснованными (во всяком случае, я мог бы сказать, зачем я так сделал), но этот код очевидно не скомпилируется и работать не будет. Но внешне — все выглядит довольно неплохо, названия функций, какое-то подобие семантики вызовов — все правдоподобно, но…
В общем, вы понимаете то чувство, когда ты думаешь, что со студенткой разговаривал, а на самом деле — с большим тараканом, с жуком-оборотнем.
Решил проверить догадку самостоятельно и задал ChatGPT вот такую задачу: Write a C language program for RIOT OS that uses a BME280 sensor connected by I2C bus, reads temperature, pressure and humidity values from the sensor and outputs them into UART each 10 seconds. Also, if the temperature is higher than 100 degrees Fahrenheit, a LED connected to one of GPIO pins must be switched on. When the temperature lowers, the LED is switched off.
Я думаю, вы уже догадались, что было ответом — правильно, третий вариант API! (но с градусами Фаренгейта я хорошую подставу придумал):
#include "bme280.h"
#include "periph/gpio.h"
#include "periph/i2c.h"
#include "periph/uart.h"
#include "xtimer.h"
#define I2C_DEV (I2C_DEV(0))
#define BME280_ADDR (0x76)
#define LED_PIN (GPIO_PIN(PORT_A, 5))
#define LED_ON (0)
#define LED_OFF (1)
static bme280_t dev;
static gpio_t led;
static void init(void)
{
i2c_init(I2C_DEV);
bme280_init(&dev, I2C_DEV, BME280_ADDR);
uart_init(UART_DEV(0), 115200, UART_FLAG_NONE);
gpio_init(LED_PIN, GPIO_OUT);
}
int main(void)
{
init();
while (1) {
bme280_read_fixed(&dev);
printf("Temperature: %ld.%02lu C\n", dev.temperature / 100, dev.temperature % 100);
printf("Pressure: %lu.%02lu hPa\n", dev.pressure / 100, dev.pressure % 100);
printf("Humidity: %lu.%02lu %%\n", dev.humidity / 1024, (dev.humidity * 100) / 1024 % 100);
if (dev.temperature > 100 * 100) {
gpio_write(led, LED_ON);
} else {
gpio_write(led, LED_OFF);
}
xtimer_sleep(10);
}
return 0;
}

Но вот что интересно — так это время, которое пройдет между написанием кода и обнаружением наебалова. Принято считать, что одна из сложностей в эмбеддеде всех мастей — это долгий цикл обратной связи между написанием кода и получением результата — работает/не работает/надо переделать. Так вот, для наебалова в таком вот духе он сокращается до одной команды в консоли — наберите make flash
и тут же, не отходя от кассы, получите тугую струю ссанины в ебало в виде совершенно невнятных ошибок компилятора. А вот если у вас модный язык вроде Javascript или Python — то с вот таким синтаксически корректный бредом можно долго и плодотворно заниматься debugging into existence. Программист программировает, получька капает.
Будующее такое яркое.