Как преобразовать шаблон из C ++ в C - PullRequest
0 голосов
/ 24 июня 2019

Я пытаюсь преобразовать некоторый код C ++ в C для моего компилятора, который не может работать с кодом C ++.Я хотел бы создать шаблон ниже для C. Этот шаблон преобразует десятичное целое число в шестнадцатеричное и добавляет 0 перед значением, если размер шестнадцатеричной строки меньше (sizeof(T)*2).Тип данных T может быть unsigned char, char, short, unsigned short, int, unsigned int, long long и unsigned long long.

template< typename T > std::string hexify(T i)
{
    std::stringbuf buf;
    std::ostream os(&buf);
    os << std::setfill('0') << std::setw(sizeof(T) * 2)
       << std::hex << i;
    std::cout<<"sizeof(T) * 2 = "<<sizeof(T) * 2<<"   buf.str() = "<<buf.str()<<"   buf.str.c_str() = "<<buf.str().c_str()<<std::endl;
    return buf.str().c_str();
}

Спасибо.Вы за помощь в туре.

Редактировать 1: я пытался использовать объявление

char * hexify (void data, size_t data_size)

, но когда я вызываю со значением int int_value:

char * result = hexify(int_value, sizeof(int)) 

, оно неработать из-за:

неконкурентного типа (void и int).

Так что, в этом случае я должен использовать макрос?Я не пробовал с макросом, потому что это сложно.

Ответы [ 3 ]

3 голосов
/ 24 июня 2019

C не имеет шаблонов.Одним из решений является передача максимально поддерживаемого целого числа по ширине (uintmax_t, в Value ниже) и размера исходного целого числа (в Size).Одна подпрограмма может использовать размер, чтобы определить количество цифр для печати.Еще одним осложнением является то, что C не предоставляет C ++ std::string автоматическое управление памятью.Типичный способ справиться с этим в C состоит в том, чтобы вызываемая функция выделяла буфер и возвращала его вызывающей стороне, которая отвечает за его освобождение по завершении.

В приведенном ниже коде показана функция hexify, которая выполняетэто, а также показывает макрос Hexify, который принимает один параметр и передает его размер и значение в функцию hexify.

Обратите внимание, что в C такие символьные константы, как 'A'имейте тип int, а не char, поэтому требуется некоторая осторожность при предоставлении нужного размера.Код ниже содержит пример для этого.

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>


char *hexify(size_t Size, uintmax_t Value)
{
    //  Allocate space for "0x", 2*Size digits, and a null character.
    size_t BufferSize = 2 + 2*Size + 1;
    char *Buffer = malloc(BufferSize);

    //  Ensure a buffer was allocated.
    if (!Buffer)
    {
        fprintf(stderr,
            "Error, unable to allocate buffer of %zu bytes in %s.\n",
            BufferSize, __func__);
        exit(EXIT_FAILURE);
    }

    //  Format the value as "0x" followed by 2*Size hexadecimal digits.
    snprintf(Buffer, BufferSize, "0x%0*" PRIxMAX, (int) (2*Size), Value);

    return Buffer;
}


/*  Provide a macro that passes both the size and the value of its parameter
    to the hexify function.
*/
#define Hexify(x)   (hexify(sizeof (x), (x)))


int main(void)
{
    char *Buffer;

    /*  Show two examples of using the hexify function with different integer
        types.  (The examples assume ASCII.)
    */

    char x = 'A';
    Buffer = hexify(sizeof x, x);
    printf("Character '%c' = %s.\n", x, Buffer);  // Prints "0x41".
    free(Buffer);

    int i = 123;
    Buffer = hexify(sizeof i, i);
    printf("Integer %d = %s.\n", i, Buffer);  // Prints "0x00007b".
    free(Buffer);

    /*  Show examples of using the Hexify macro, demonstrating that 'A' is an
        int value, not a char value, so it would need to be cast if a char is
        desired.
    */
    Buffer = Hexify('A');
    printf("Character '%c' = %s.\n", 'A', Buffer);  // Prints "0x00000041".
    free(Buffer);

    Buffer = Hexify((char) 'A');
    printf("Character '%c' = %s.\n", 'A', Buffer);  // Prints "0x41".
    free(Buffer);
}
0 голосов
/ 24 июня 2019

Вам не нужны шаблоны, если вы переходите к необработанным битам и байтам.

Если важна производительность, также лучше развернуть процедуру преобразования вручную, поскольку функции обработки строк в C и C ++ идут с большим количеством медленных накладных расходов. Несколько хорошо оптимизированная версия будет выглядеть примерно так:

char* hexify_data (char*restrict dst, const char*restrict src, size_t size)
{
  const char NIBBLE_LOOKUP[0xF+1] = "0123456789ABCDEF";
  char* d = dst;

  for(size_t i=0; i<size; i++)
  {
    size_t byte = size - i - 1; // assuming little endian
    *d = NIBBLE_LOOKUP[ (src[byte]&0xF0u)>>4 ];
    d++;
    *d = NIBBLE_LOOKUP[ (src[byte]&0x0Fu)>>0 ];
    d++;
  }
  *d = '\0';
  return dst;
}

Это разбивает любой передаваемый тип побайтово, используя тип символа. Что хорошо, особенно при использовании типов символов. Он также использует распределение вызовов для максимальной производительности. (Это также можно сделать независимым от endianess с дополнительной проверкой на цикл.)

Мы можем сделать вызов немного более удобным с помощью макроса-обёртки:

#define hexify(buf, var) hexify_data(buf, (char*)&var, sizeof(var))

Полный пример:

#include <string.h>
#include <stdint.h>
#include <stdio.h>

#define hexify(buf, var) hexify_data(buf, (char*)&var, sizeof(var))

char* hexify_data (char*restrict dst, const char*restrict src, size_t size)
{
  const char NIBBLE_LOOKUP[0xF+1] = "0123456789ABCDEF";
  char* d = dst;

  for(size_t i=0; i<size; i++)
  {
    size_t byte = size - i - 1; // assuming little endian
    *d = NIBBLE_LOOKUP[ (src[byte]&0xF0u)>>4 ];
    d++;
    *d = NIBBLE_LOOKUP[ (src[byte]&0x0Fu)>>0 ];
    d++;
  }
  *d = '\0';
  return dst;
}


int main (void)
{
  char buf[50];

  int32_t i32a = 0xABCD;
  puts(hexify(buf, i32a));

  int32_t i32b = 0xAAAABBBB;
  puts(hexify(buf, i32b));

  char c = 5;
  puts(hexify(buf, c));

  uint8_t u8 = 100;
  puts(hexify(buf, u8));
}

Выход:

0000ABCD
AAAABBBB
05
64
0 голосов
/ 24 июня 2019

необязательное решение - использовать строку формата, например printf

обратите внимание, что вы не можете вернуть указатель на локальную переменную, но вы можете получить буфер в качестве аргумента (здесь он без проверки границ).

char* hexify(char* result, const char* format, void* arg)
{
    int size = 0;
    if(0 == strcmp(format,"%d") || 0 == strcmp(format,"%u"))
    {
        size=4;
        sprintf(result,"%08x",arg);
    }
    else if(0 == strcmp(format,"%hd") || 0 == strcmp(format,"%hu"))
    {
        size=2;
        sprintf(result,"%04x",arg);
    }
    else if(0 == strcmp(format,"%hhd")|| 0 == strcmp(format,"%hhu"))
    {
        size=1;
        sprintf(result,"%02x",arg);
    }
    else if(0 == strcmp(format,"%lld") || 0 == strcmp(format,"%llu") )
    {
        size=8;
        sprintf(result,"%016x",arg);
    }
    //printf("size=%d", size);
    return result;

}

int main()
{
    char result[256];
    printf("%s", hexify(result,"%hhu", 1));

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