FastNetMon

Показаны сообщения с ярлыком C. Показать все сообщения
Показаны сообщения с ярлыком C. Показать все сообщения

понедельник, 8 февраля 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]".




пятница, 17 сентября 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/

суббота, 15 мая 2010 г.

C, strlen

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

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

четверг, 4 марта 2010 г.

воскресенье, 7 февраля 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.


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

четверг, 14 января 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 он вопщем.