[英]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.