FastNetMon

Showing posts with label C++. Show all posts
Showing posts with label C++. Show all posts

Monday, 8 February 2016

Проблемы при использовании union и bit fields в C++

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

Но, к сожалению, при их совместном использовании возможны очень неприятные проблемы, от которых довольно сложно защититься - кейс странный и неоднозначный.

Вот пример проблемного кода, который выглядит на первый взгляд нормально и корректно: https://gist.github.com/pavel-odintsov/71538a198a0ba53ea156

Для удобства привожу основную структуру данных здесь:
typedef union __attribute__((__packed__)) {
    uint16_t reserved_flag : 1, dont_fragment_flag : 1, more_fragments_flag : 1, fragment_offset : 13;
    uint16_t fragmentation_details_as_integer;
} fragmentation_details_t;

Как можно видеть, идея была в том, чтобы иметь доступ к блоку из 4х битовых полей как к одному 16 битному целому (для удобства операций и оптимизации).

Но на деле этот код работает вовсе не так. А работать он будет так, что все 5 переменных будут разделять общую память с одинаковым смещением! То есть, установив одно из однобитовых битовых полей мы сразу же установим все прочие - так как они использую один и тот же адрес.

Как выглядит верное решение данной задачи?

Выглядит оно так - нужно внести дополнительную структур:
typedef union __attribute__((__packed__)) {
     struct { uint16_t fragment_offset : 13, more_fragments_flag : 1, dont_fragment_flag : 1, reserved_flag : 1;
    } fragmentation_details_pretty;

    uint16_t fragmentation_details_as_integer;
} fragmentation_details_t;

Такой подход не так красив, как задуманный ранее, потому что С и С++ не позволяют делать анонимные структуры и добавляется отдельный уровень вложенности. Но вот задачу данный подход решает на отлично! 

Update: как подсказал Andrew Stromnov, можно сделать намного круче - использовать GCC расширение и сделать анонимную структуру:

typedef union __attribute__((__packed__)) {
  struct {
    uint16_t fragment_offset : 13, more_fragments_flag : 1, dont_fragment_flag : 1, reserved_flag : 1; };
    uint16_t fragmentation_details_as_integer
} fragmentation_details_t;

В таком случае при доступе к полям нам не нужно будет добавлять вложенную структуру! НА мой взгляд, это серьезное удобство и ради него я согласен пойти на использование расширений стандарта :) Хотя, вроде бы в С11 эта фича в стандарте! Но не в С++, увы, пока такой фичи в С++ нету.

Учтите, в режиме pedantic будут жалобы "../isolated_example.cpp:13:5: warning: ISO C++ prohibits anonymous structs [-Wpedantic]" и "warning: anonymous structs are a GNU extension [-Wgnu-anonymous-struct]".




Friday, 17 September 2010

CentOS: компиляция 32 битного ПО на 64 битной платформе

При попытке скомпилировать программу имеем баг:
cc -m32 test.c
In file included from /usr/include/features.h:352,
from /usr/include/sys/poll.h:23,
from /usr/include/poll.h:1,
from ABftw_c.c:42:
/usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: No such file or directory

Чинится это так:
yum -y install glibc-devel

Источник: http://www.cyberciti.biz/faq/x86_64-linux-error-gnustub-32h-missing-error-and-solution/

Saturday, 15 May 2010

C, strlen

Что вернет
strlen("1\0")
?

1, так как \0 при этом не учитывается, так как является терминирующим символом. Но вот при выделении памяти про него стоит помнить. Индекс же \0 в строке будет = 1, то есть strlen("1\0").

Thursday, 4 March 2010

Люди! Никогда не пытайтесь засунуть строкове представление int в char[8], ни-ког-да!!!

Да, тупость это плохо :) Но не стоит забывать, что int - это 8 знаков + окончание строки \0 и оно-то как раз не лезет, поэтому получается всякая муть.

Sunday, 7 February 2010

Смена имени программы при запуске


/*
* Copyright (c) 1997-1999 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/

#include <unistd.h>

int main(int argc, char ** argv) {
if (argc<2) return 1; execvp(argv[1], argv + 2); return 1; }



Компилировать так:

gcc doexec.c -o doexec


Использовать так:

./doexec /usr/bin/perl new_name -e 'while(){}'


И теперь если в другой консоли посмотреть имя процесса, то оно будет вот такое:

root 32576 92.0 0.0 100468 1556 pts/0 R+ 03:49 0:06 new_name -e while(){}


Теперь немного теории о том, как это работает:

The execv() and execvp() functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program. The first argument, by convention, should point to the filename associated with the file being executed. The array of pointers must be terminated by a NULL pointer.


Одно прошу - не спрашивайте, зачем мне это понадобилось :)))

Thursday, 14 January 2010

Какой размер enum в C?

An enum is only guaranteed to be large enough to hold int values. The compiler is free to choose the actual type used based on the enumeration constants defined so it can choose a smaller type if it can represent the values you define. If you need enumeration constants that don't fit into an int you will need to use compiler-specific extensions to do so.


(c) http://stackoverflow.com/questions/366017/what-is-the-size-of-an-enum-in-c

Ну int он вопщем.

Monday, 23 June 2008

KLone: каркас для web-программирования на языке C.

Вот довольно давно отрыл вот такую вот весьма извращенную вещь: KLone: каркас для web-программирования на языке C.

Может кому пригодится, у самого пока руки не дошли попробовать.