С указателями и вопросом установки бита - PullRequest
3 голосов
/ 04 февраля 2011

В качестве фона для этого вопроса я написал тестовую программу, чтобы исследовать странное поведение, которое мы наблюдали в программе обмена сообщениями, над которой я работаю.У нас есть различные структуры, которые используют битовые флаги для хранения состояний сообщений, некоторые флаги используют символ, некоторые используют шорты.Утилита, которую мы должны выгрузить сообщения в плоские файлы, использовала char * для этих значений флага, чтобы извлечь настройки, поэтому я намеренно использовал другой указатель на flag2.

Когда эта программа работает в AIX UNIX6.1 Почему вывод:

2 установлено
4 установлено
8 установлено
16 установлено
64 установлено

Что произошло со значениями 1 и 32?

#include <stdio.h>

#define SET(x,y) y |= (x)
#define UNSET(x,y) y &= (~x)

int main ( int argc, char *argv[] )
{
    unsigned char *g;
    unsigned short *h;
    unsigned long *i;

    char flag1; 
    short flag2; 
    long flag3;

    g = (char*) &flag2;

    SET(1, flag2);
    if ( 1 & *g )
        printf("1 set\n");
    UNSET(1, flag2);

    SET(2, flag2);
    if ( 2 & *g )
        printf("2 set\n");
    UNSET(2, flag2);

    SET(4, flag2);
    if ( 4 & *g )
        printf("4 set\n");
    UNSET(4, flag2);

    SET(8, flag2);
    if ( 8 & *g )
        printf("8 set\n");
    UNSET(8, flag2);

    SET(16, flag2);
    if ( 16 & *g )
        printf("16 set\n");
    UNSET(16, flag2);

    SET(32, flag2);
    if ( 32 & *g )
        printf("32 set\n");
    UNSET(32, flag2);

    SET(64, flag2);
    if ( 64 & *g )
        printf("64 set\n");
    UNSET(64, flag2);

    return 0;
}

Ответы [ 3 ]

4 голосов
/ 04 февраля 2011

AIX - это архитектура с прямым порядком байтов, то есть g указывает на самые значимые байты flag. Это означает, что любые изменения в младших значащих байтах невидимы для g.

flag2 также никогда не инициализируется, поэтому он будет содержать некоторые произвольные значения. Так что получается, что вы думаете, что некоторые настройки битов сработали, когда это были просто произвольные значения, которые были в начале.

Если вы работаете на машине с прямым порядком байтов, например x86, все должно работать так, как ожидалось.

0 голосов
/ 04 февраля 2011

Из указателей Википедии :

Проект стандарта С 2005 года требует, чтобы приведение указателя происходит от одного типа до одного из другой тип должен поддерживать правильность выравнивания для обоих типов (6.3.2.3 Указатели, пар. 7): [3]

char *external_buffer = "abcdef";
int *internal_data;

internal_data = (int *)external_buffer;  // UNDEFINED BEHAVIOUR if "the resulting pointer
                                         // is not correctly aligned"

Итог: используйте правильный тип указателя

Поведение может работать как ожидалось, но не гарантировано.

C ++ 03 Standard $ 5.3.3 / 1 говорит,

sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1; the

результат sizeof применяется к любому другому Основной тип (3.9.1) реализации. [Примечание: в в частности, sizeof (bool) и sizeof (wchar_t) реализация defined.69)

Посмотрите на это: C ++ Размер примитивов

0 голосов
/ 04 февраля 2011

Я вижу несколько вещей, которые могут быть проблемой.

  1. Вы не инициализируете flag2

  2. Возможно, вы захотитедля приведения g= (short * ) &flag2, потому что если вы приведете к типу char, вы не обязательно получите ссылку на младшие 8 бит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...