簡體   English   中英

如何將無符號長轉換為字符串

[英]How to convert unsigned long to string

在 C 語言中,如何將unsigned long值轉換為字符串( char * )並保持我的源代碼可移植或只是重新編譯它以在其他平台上工作(無需重寫代碼?

例如,如果我有sprintf(buffer, format, value) ,如何以獨立於平台的方式確定緩沖區的大小?

const int n = snprintf(NULL, 0, "%lu", ulong_value);
assert(n > 0);
char buf[n+1];
int c = snprintf(buf, n+1, "%lu", ulong_value);
assert(buf[n] == '\0');
assert(c == n);

標准方法是使用sprintf(buffer, "%lu", value); value的字符串 rep 寫入buffer 但是,溢出是一個潛在的問題,因為sprintf會愉快地(並且在不知不覺中)寫入緩沖區的末尾。

這實際上是 sprintf 的一大弱點,通過使用流而不是緩沖區在 C++ 中部分修復。 通常的“答案”是分配一個不太可能溢出的非常大的緩沖區,讓 sprintf 輸出到那個,然后使用 strlen 確定產生的實際字符串長度,調用一個(那個大小 + 1)的緩沖區並將字符串復制到那個.

本網站詳細討論了這個問題和相關問題。

一些庫提供snprintf作為替代方案,可讓您指定最大緩沖區大小。

您可以編寫一個從 unsigned long 轉換為 str 的函數,類似於 ltostr 庫函數。

char *ultostr(unsigned long value, char *ptr, int base)
{
  unsigned long t = 0, res = 0;
  unsigned long tmp = value;
  int count = 0;

  if (NULL == ptr)
  {
    return NULL;
  }

  if (tmp == 0)
  {
    count++;
  }

  while(tmp > 0)
  {
    tmp = tmp/base;
    count++;
  }

  ptr += count;

  *ptr = '\0';

  do
  {
    res = value - base * (t = value / base);
    if (res < 10)
    {
      * -- ptr = '0' + res;
    }
    else if ((res >= 10) && (res < 16))
    {
        * --ptr = 'A' - 10 + res;
    }
  } while ((value = t) != 0);

  return(ptr);
}

您可以在這里參考我的博客,其中通過示例解釋了實現和使用。

char buffer [50];

unsigned long a = 5;

int n=sprintf (buffer, "%lu", a);

嘗試使用sprintf

unsigned long x=1000000;
char buffer[21];
sprintf(buffer,"%lu", x);

編輯:

請注意,您必須提前分配一個緩沖區,並且不知道這樣做時數字實際上會持續多長時間。 我假設 32bit long s,它可以產生多達 10 位的數字。

有關所涉及問題的更好解釋,請參閱 Carl Smotricz 的回答。

對於長值,您需要為無符號十進制整數添加長度信息“l”和“u”,

作為可用選項的參考,請參閱sprintf

#include <stdio.h>

    int main ()
    {
      unsigned long lval = 123;
      char buffer [50];
      sprintf (buffer, "%lu" , lval );
     }

...如何以獨立於平台的方式確定緩沖區的大小?

unsigned long轉換為字符串的挑戰之一是如何確定所需的字符串大小。

  • 動態地

反復將該值除以 10 直到 0 以找到size_needed

value_copy = value;
unsigned size_needed = 1; // For the null character.
if (value_copy < 0) size_needed++; // Only needed for signed types.
do {
  size_needed++; // Add 1 per digit.
  value_copy /= 10;
} while (value_copy != 0);
  • 更糟糕的情況下

查找ULONG_MAX的字符串長度。
從漂亮的IMAX_BITS(m)開始,它返回梅森數中的位數,如ULONG_MAX (即使類型有填充,這也會給我們最大位寬。)然后按 log 10 2 (0.301...) 縮放以找到小數位數並添加 2 進行舍入和空字符。

#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define LOG2_10_N  28
#define LOG2_10_D  93
#define UNSIGNED_LONG_STRING_SIZE (IMAX_BITS(ULONG_MAX)*LOG2_10_N/LOG2_10_D + 2)
// Slightly different for signed types, one more for the sign:
#define SIGNED_LONG_STRING_SIZE   (IMAX_BITS( LONG_MAX)*LOG2_10_N/LOG2_10_D + 3)

有了字符串大小,接下來有很多可能的步驟。 我喜歡使用 C99(和更高版本)的復合文字來形成所需的空間。 該空間在塊結束之前有效。

char *unsigned_long_to_string(char *dest, unsigned long x) {
  sprintf(dest, "%lu", x);
  return dest;
}

// Compound literal                                        v-----------------------------------v
#define UNSIGNED_LONG_TO_STRING(u) unsigned_long_to_string((char [UNSIGNED_LONG_STRING_SIZE]){0}, (u))

int main(void) {
  puts(UNSIGNED_LONG_TO_STRING(42));
  puts(UNSIGNED_LONG_TO_STRING(ULONG_MAX));
}

輸出

42
18446744073709551615  // This varies

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM