在C语言中将字符数组转换为长整型

6
这个问题可能看起来有些愚蠢,请指导我。 我有一个将长数据转换为字符数组的函数。
void ConvertLongToChar(char *pSrc, char *pDest)
{
    pDest[0] = pSrc[0];
    pDest[1] = pSrc[1];
    pDest[2] = pSrc[2];
    pDest[3] = pSrc[3];
}

And I call the above function like this

long lTemp = (long) (fRxPower * 1000);
ConvertLongToChar ((char *)&lTemp, pBuffer);

这个工作得很好。 我需要一个类似的函数来反转这个过程。将字符数组转换为长整型。 我不能使用atol或类似的函数。

9个回答

11

留下与您的其他函数匹配字节序的负担,这是一种方法:

unsigned long int l = pdest[0] | (pdest[1] << 8) | (pdest[2] << 16) | (pdest[3] << 24);

为了确保安全,这里是相应的反方向:

unsigned char pdest[4];
unsigned long int l;
pdest[0] = l         & 0xFF;
pdest[1] = (l >>  8) & 0xFF;
pdest[2] = (l >> 16) & 0xFF;
pdest[3] = (l >> 24) & 0xFF;

char[4]转换成长整型再转回来是完全可逆的;将长整型转换成char[4]再转回来只能保证值小于2^32-1时可逆。

需要注意的是,这一切仅对无符号类型有定义。

(如果你从左到右读取pdest,我的示例是小端字节序。)

补充说明:我还假设CHAR_BIT == 8。在代码中,通常需要将8的倍数替换为CHAR_BIT的倍数。


11

你可以这样做:

union {
 unsigned char c[4];
 long l;
} conv;

conv.l = 0xABC;

并访问c [0] c [1] c [2] c [3]。 这很好,因为它不浪费内存,并且非常快,因为除了初始赋值之外,没有任何移位或任何其他赋值操作,并且可以双向工作。


5
根据C++标准,这也被称为未定义行为。 :) - jalf
2
@jalf 这是一个关于 C 语言的问题。 - Engineer
2
@NickWiggill 好的,根据C标准,这也是未定义行为。 :) - jalf
我非常确定,在gcc和MS编译器下,这不是未定义行为。它可能是由C标准引起的。 - Vinicius Kamakura
3
尽管您正确,但编译器的工作实际上对于标准的表述并不具有信息性。C99及以后版本明确规定了可以通过union进行类型转换:https://dev59.com/-2gu5IYBdhLWcg3wBym1。然而,C++没有继承这个特性。 - underscore_d

10

一种简单的方法是使用memcpy:

char * buffer = ...;
long l;
memcpy(&l, buff, sizeof(long));

然而,这并没有考虑字节序的问题,所以如果你需要在多台计算机之间共享数据,请注意。


我尝试了你的例子,但它对我不起作用。而能够工作的是非常相似的东西:long vOut = strtol(vIn,NULL,10); - Beezer
1
@Beezer,这是完全不同的事情:你的方法将文本解析为数字,而我的方法将缓冲区的字节解释为长整型。这些是不同的问题。 - Etienne de Martel

4
如果您想将 sizeof(long) 字节的内存视为单个长整型,那么应该按照以下方式操作:
char char_arr[sizeof(long)];
long l;

memcpy (&l, char_arr, sizeof (long));

可以通过按位移动和粘贴每个长字节来完成此操作,如下所示。

l = 0;
l |= (char_arr[0]);
l |= (char_arr[1] << 8);
l |= (char_arr[2] << 16);
l |= (char_arr[3] << 24);

如果您想将字符串"1234\0"转换为1234L,则应该:
l = strtol (char_arr, NULL, 10); /* to interpret the base as decimal */

0

这个能用吗:

#include<stdio.h>

long ConvertCharToLong(char *pSrc) {
    int i=1;
    long result = (int)pSrc[0] - '0';
    while(i<strlen(pSrc)){
         result = result * 10 + ((int)pSrc[i] - '0');
         ++i;
    }
    return result;
}


int main() {
    char* str = "34878";
    printf("The answer is %d",ConvertCharToLong(str));
    return 0;
}

它不起作用,因为char数组不会直接存储长整型值,而是以字节为单位存储。感谢你的回答。 - AjayR
你的例子是正确的。但在我的情况下,存储的不是长数据而是字节,所以这个解决方案对我不起作用。 - AjayR

0
unsigned long long convert_achar_to_unsigned_long_long(char *src) {
  unsigned long long ret = 0;
  char digit[2];
  digit[1] = '\0';
  byte n = 0;
  while(src[n] != '\0') {    
    digit[0] = src[n];
    if(n!=0) {
      ret *= 10;
    }  
    ret += atoi(digit);
    n++;
  }
  return ret;
}

2
这个实现与OP的问题无关,而且对于它的目的来说效率不高:检查一个数字并使用src[n] - '0'而不是atoi(digit) - undefined

-1

这很不规范,但它能用:

unsigned char myCharArray[8];
// Put some data in myCharArray here...
long long integer = *((long long*) myCharArray);

1
这是错误的,别名错误和可能由错误对齐导致的未定义行为。 - Antti Haapala -- Слава Україні

-1
char charArray[8]; //ideally, zero initialise
unsigned long long int combined = *(unsigned long long int *) &charArray[0];

要小心空终止的字符串,因为你会复制任何字节到combined中,甚至是在空终止符之后的字节;因此,在上面的赋值中,charArray需要完全零初始化以进行“干净”的转换。


这是错误的,别名错误并且由于错误对齐可能会导致未定义的行为。 - Antti Haapala -- Слава Україні

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接