Безопасно каламбурящий символ* для удвоения в C

Если вы в порядке с использованием exec () и изменили ваши str_key (s), вы можете сделать что-то вроде:

def get_keys_value(string):
    keys, value = string.split("=")
    return keys, value

def get_exec_string(dict_name, keys):
    exec_string = dict_name
    for key in keys.split("."):
        exec_string = exec_string + "[" + key + "]"
    exec_string = exec_string + "=" + "value"
    return exec_string

str_key_1 = "'user'.'username'=john"
str_key_2 = "'user'.'name'.'last'=henry"
str_key_list = [str_key_1, str_key_2]

for str_key in str_key_list:
    keys, value = get_keys_value(str_key) # split into key-string and value
    exec_string = get_exec_string("a", keys) # extract keys from key-string 
    exec(exec_string)

print(a)
# prints {'user': {'email': 'micheal@domain.com', 'name': {'last': 'henry', 'first': 'Micheal'}, 'username': 'john'}}
11
задан Community 23 May 2017 в 12:30
поделиться

5 ответов

Так как Вы, кажется, знаете достаточно о своей реализации, чтобы быть уверенными, что int64_t и дважды являются тем же размером и имеют подходящие представления устройства хранения данных, Вы могли бы рисковать memcpy. Затем Вы не должны даже думать об искажении.

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

int64_t i = slittleint64_t(buffoffset);
double d;
memcpy(&d,&i,8); /* might emit no code if you're lucky */
printf("%lf", d);

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

В целом, тем не менее, выполнение чего-либо слишком умного с byteswapping приводит к проблемам мобильности. Там существуйте, ABIs с промежуточным порядком байтов удваивается, где каждое слово является прямым порядком байтов, но хвастовство на первом месте.

Обычно Вы могли полагать, что хранение Вашего удваивает использование sprintf и sscanf, но для Вашего проекта форматы файлов не находятся под Вашим контролем. Но если Ваше приложение просто сгребает IEEE, удваивается из входного файла в одном формате к выходному файлу в другом формате (не уверенный, если это, так как я не знаю рассматриваемые форматы базы данных, но раз так), затем возможно, можно забыть о том, что это - двойное, так как Вы не используете его для арифметики так или иначе. Просто рассматривайте его как непрозрачный символ [8], требуя byteswapping, только если форматы файлов отличаются.

2
ответ дан 3 December 2019 в 08:06
поделиться

Я высоко предполагаю, что Вы читаете Понимающее Строгое Искажение. А именно, посмотрите, что разделы маркировали "Casting through a union". Это имеет много очень хороших примеров. В то время как статья находится на веб-сайте о процессоре Cell и использует примеры блока PPC, почти все это одинаково применимо к другой архитектуре, включая x86.

12
ответ дан 3 December 2019 в 08:06
поделиться

Как очень небольшое подпредложение, я предлагаю, чтобы Вы занялись расследованиями, если можно подкачать маскирование и смещение в 64-разрядном случае. Так как операция подкачивает байты, необходимо смочь всегда сойти с рук маску просто 0xff. Это должно привести к более быстрому, более компактному коду, если компилятор не достаточно умен, чтобы полагать что один сам.

Короче говоря, изменение этого:

(((wrongend & 0xff00000000000000LL) >> 56)

в это:

((wrongend >> 56) & 0xff)

должен генерировать тот же результат.

0
ответ дан 3 December 2019 в 08:06
поделиться

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

Макросы обычно являются плохой идеей, но это могло бы быть исключением из правила. Должно быть возможно получить подобное шаблону поведение в C использование ряда макросов с помощью входных и выходных типов в качестве параметров.

2
ответ дан 3 December 2019 в 08:06
поделиться

Править:
Удаленные комментарии относительно того, как эффективно всегда хранить данные обратный порядок байтов и подкачивающий к порядку байтов машины как корреспондент, не упомянули, что другая программа пишет его данные (который является важной информацией).

Все еще, если данным нужно преобразование от какого-либо порядка байтов до большого и от большого для хостинга порядка байтов, ntohs/ntohl/htons/htonl являются лучшими методами, самыми изящными и непобедимыми в скорости (поскольку они выполнят задачу в аппаратных средствах, если поддержки ЦП, что, Вы не можете победить это).


Относительно двойного/плавающего просто сохраните их к ints кастингом памяти:

double d = 3.1234;
printf("Double %f\n", d);
int64_t i = *(int64_t *)&d;
// Now i contains the double value as int
double d2 = *(double *)&i;
printf("Double2 %f\n", d2);

Перенесите его в функцию

int64_t doubleToInt64(double d)
{
    return *(int64_t *)&d;
}

double int64ToDouble(int64_t i)
{
    return *(double *)&i;
}

Корреспондент предоставил эту ссылку:

http://cocoawithlove.com/2008/04/using-pointers-to-recast-in-c-is-bad.html

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

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

Это не опасно вообще, и это - также не плохая практика. Это имеет только потенциал для порождения ошибок, если Вы делаете это неправильно, точно так же, как программирование в C имеет потенциал для порождения ошибок, если Вы делаете это неправильно, также - какое-либо программирование на каком-либо языке. Тем аргументом необходимо прекратить программировать в целом.

Введите трамбовку
Форма искажения указателя, где два указателя и относятся к тому же местоположению в памяти, но представляют то местоположение как различные типы. Компилятор будет рассматривать обе "игры слов" как несвязанные указатели. Трамбовка типа имеет потенциал для порождения проблем зависимости для любых данных, к которым получают доступ через оба указателя.

Это верно, но к сожалению полностью не связано с моим кодом.

То, к чему он обращается, является кодом как это:

int64_t * intPointer;
:
// Init intPointer somehow
:
double * doublePointer = (double *)intPointer;

Теперь doublePointer и intPointer обе точки к той же ячейке памяти, но рассматривающий это как тот же тип. Это - ситуация, которую необходимо решить с объединением действительно, что-либо еще довольно плохо. Плохо это не то, что делает мой код!

Мой код копирует значением, не ссылкой. Я бросил вдвое большее по сравнению с int64 указателем (или наоборот) и сразу отсрочка это. После того как функции возвращаются, нет никакого указателя, придерживался чего-либо. Существует int64 и двойное, и они полностью не связаны с входным параметром функций. Я никогда не копирую указателя на указатель другого типа (если Вы видели это в моем примере кода, Вы сильно неправильно читаете код C, который я написал), я просто передаю значение переменной другого типа (в собственной ячейке памяти). Таким образом, определение трамбовки типа не применяется вообще, как это говорит, "относятся к тому же местоположению в памяти", и ничто здесь не относится к той же ячейке памяти.

int64_t intValue = 12345;
double doubleValue = int64ToDouble(intValue);
// The statement below will not change the value of doubleValue!
// Both are not pointing to the same memory location, both have their
// own storage space on stack and are totally unreleated.
intValue = 5678;

Мой код является не чем иным как копией памяти, просто записанной в C без внешней функции.

int64_t doubleToInt64(double d)
{
    return *(int64_t *)&d;
}

Мог быть записан как

int64_t doubleToInt64(double d)
{
    int64_t result;
    memcpy(&result, &d, sizeof(d));
    return result;
}

Именно не что иное как, таким образом, нет никакого типа, каламбурящего даже в поле зрения нигде. И эта работа также полностью безопасна, так безопасна, как операция может быть в C. Двойное определяется, чтобы всегда быть 64 бита (в отличие от интервала, он не варьируется по размеру, он фиксируется на уровне 64 битов), следовательно он будет всегда вписываться в измеренную переменную int64_t.

-1
ответ дан 3 December 2019 в 08:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: