Привет всем кодерам C.
Сначала посмотрев похожие вопросы, я не смог их найти.
Как извлечь / сравнить 4 байта в переносном режиме (конечно, без memcpy / memcmp)?
Я никогда не изучал C, и поэтому я являюсь живым доказательством того, что без знания основ все становится неприятным беспорядком.
В любом случае, написание слов (уже) не время говорить «начни с алфавита».
ulHashPattern = *(unsigned long *)(pbPattern);
for (a=0; a < ASIZE; a++) bm_bc[a]=cbPattern;
for (j=0; j < cbPattern-1; j++) bm_bc[pbPattern[j]]=cbPattern-j-1;
i=0;
while (i <= cbTarget-cbPattern) {
if ( *(unsigned long *)&pbTarget[i] == ulHashPattern ) {
Приведенный выше фрагмент работает так же, как и на 32-битном компиляторе Windows. Я хочу, чтобы все такие сравнения 4vs4 работали и под 64-битными Windows и Linux.
Много раз мне нужно передавать 2,4,8 байта, в приведенном выше примере мне нужно явно 4 байта от некоторого смещения pbTarget. Здесь актуальный вопрос: какой тип я должен использовать вместо unsigned long ? (думаю, что-то близкое к UINT16, UINT32, UINT64 подойдет). Другими словами, какие 3 типа мне нужны, чтобы представлять 2,4,8 байта ВСЕГДА независимо от среды.
Я считаю, что этот основной вопрос вызывает много проблем, поэтому его следует уточнить.
Дополнение 2012-Янв-16:
@ Ричард Дж. Росс III
Я в недоумении! Поскольку я не знаю, использует ли Linux 1] или 2], то есть _STD_USING определен в Linux,
другими словами, какая группа переносима: типы uint8_t, ..., uint64_t или _CSTD uint8_t, ..., _ CSTD uint64_t?
1] Отрывок из MVS 10.0 stdint.h
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef _ULonglong uint64_t;
2] Отрывок из MVS 10.0 stdint.h
#if defined(_STD_USING)
...
using _CSTD uint8_t; using _CSTD uint16_t;
using _CSTD uint32_t; using _CSTD uint64_t;
...
С Microsoft C 32bit проблем нет:
; 3401 : if ( *(_CSTD uint32_t *)&pbTarget[i] == *(_CSTD uint32_t *)(pbPattern) )
01360 8b 04 19 mov eax, DWORD PTR [ecx+ebx]
01363 8b 7c 24 14 mov edi, DWORD PTR _pbPattern$GSCopy$[esp+1080]
01367 3b 07 cmp eax, DWORD PTR [edi]
01369 75 2c jne SHORT $LN80@Railgun_Qu@6
Но когда 64-битным является целевой код, вот что происходит:
D:\_KAZE_Simplicius_Simplicissimus_Septupleton_r2-_strstr_SHORT-SHOWDOWN_r7>cl /Ox /Tcstrstr_SHORT-SHOWDOWN.c /Fastrstr_SHORT-SHOWDOWN /w /FAcs
Microsoft (R) C/C++ Optimizing Compiler Version 15.00.30729.01 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
strstr_SHORT-SHOWDOWN.c
strstr_SHORT-SHOWDOWN.c(1925) : fatal error C1083: Cannot open include file: 'stdint.h': No such file or directory
D:\_KAZE_Simplicius_Simplicissimus_Septupleton_r2-_strstr_SHORT-SHOWDOWN_r7>
Как насчет Linux 'stdint.h, он всегда представлен?
Я не сдался и прокомментировал это: //#include <stdint.h>
, тогда компиляция прошла нормально:
; 3401 : if ( !memcmp(&pbTarget[i], &ulHashPattern, 4) )
01766 49 63 c4 movsxd rax, r12d
01769 42 39 2c 10 cmp DWORD PTR [rax+r10], ebp
0176d 75 38 jne SHORT $LN1@Railgun_Qu@6
; 3401 : if ( *(unsigned long *)&pbTarget[i] == ulHashPattern )
01766 49 63 c4 movsxd rax, r12d
01769 42 39 2c 10 cmp DWORD PTR [rax+r10], ebp
0176d 75 38 jne SHORT $LN1@Railgun_Qu@6
Это очень 'unsigned long *' беспокоит меня, так как gcc -m64 будет получать QWORD, а не DWORD, верно?
@ Mysticial
Просто хотел показать три разных перевода, выполненных Microsoft CL 32bit v16:
1]
; 3400 : if ( !memcmp(&pbTarget[i], pbPattern, 4) )
01360 8b 04 19 mov eax, DWORD PTR [ecx+ebx]
01363 8b 7c 24 14 mov edi, DWORD PTR _pbPattern$GSCopy$[esp+1080]
01367 3b 07 cmp eax, DWORD PTR [edi]
01369 75 2c jne SHORT $LN84@Railgun_Qu@6
2]
; 3400 : if ( !memcmp(&pbTarget[i], &ulHashPattern, 4) )
01350 8b 44 24 14 mov eax, DWORD PTR _ulHashPattern$[esp+1076]
01354 39 04 2a cmp DWORD PTR [edx+ebp], eax
01357 75 2e jne SHORT $LN83@Railgun_Qu@6
3]
; 3401 : if ( *(uint32_t *)&pbTarget[i] == ulHashPattern )
01350 8b 44 24 14 mov eax, DWORD PTR _ulHashPattern$[esp+1076]
01354 39 04 2a cmp DWORD PTR [edx+ebp], eax
01357 75 2e jne SHORT $LN79@Railgun_Qu@6
Первоначальная цель состояла в том, чтобы извлечь (с помощью одной команды mov соответственно * (uint32_t *) & pbTarget [i]) и сравнить 4 байта с регистровой переменной длиной 4 байта, то есть одна оперативная память получает одно сравнение в одной инструкции.
К счастью, мне удалось только уменьшить доступ к 3 оперативной памяти memcmp () (применяется к pbPattern, который указывает на 4 или более байтов) до 2, к счастью, для встраивания.
Теперь, если я хочу использовать memcmp () на первых 4 байтах pbPattern (как в 2]), ulHashPattern не должен иметь тип register, тогда как 3] не нуждается в таком ограничении.
; 3400 : if ( !memcmp(&pbTarget[i], &ulHashPattern, 4) )
Строка выше выдает ошибку (ulHashPattern определяется как: зарегистрировать unsigned long ulHashPattern;):
strstr_SHORT-SHOWDOWN.c(3400) : error C2103: '&' on register variable
Да, вы правы: memcmp () сохраняет ситуацию (но с ограничением) - фрагмент 2] идентичен 3] мой грязный стиль.
Очевидно, мое стремление не использовать функцию, когда она может быть закодирована вручную, осталось в прошлом, но мне это нравится.
Тем не менее, я не совсем доволен компиляторами, я определил ulHashPattern как переменную регистра, но она загружается каждый раз из ОЗУ ?! Возможно, я что-то упускаю, но эта самая строка (mov eax, DWORD PTR _ulHashPattern $ [esp + 1076]) снижает производительность - на мой взгляд, это ужасный код.