将 uint8_t[] 转换为 IP 地址字符串
Converting an uint8_t[] to an IP address string
我目前正在学习 C。我的生态系统包括 Espressif ESP-32 微控制器和 Eclipse CDT IDE。
我正在尝试将 uint8_t[]
转换为人类可读的 IPv4 address string
。到目前为止,我想出了以下代码:
void app_main() {
uint8_t[] ip = {192, 168, 0, 99};
dump_ip(ip);
}
void dump_ip(const uint8_t *in) {
// ip addresses consist of three dots + terminator '[=11=]'
int size = 4;
// count amount of chars needed for specific ip address
for(int i=0; i<4; i++) {
if(in[i]==0) {
size ++;
} else {
size += ((int)log10(in[i]))+1;
}
}
// allocate memory on heap for an ip address of length 'size'
char *ip_str = (char*)malloc(size*sizeof(char));
// copy ip address parts to char array
int pos = 0;
for(int i=0; i<4; i++) {
if(in[i]==0) {
ip_str[pos] = '0';
pos++;
} else {
char b[4];
itoa(in[i], b, 10);
for(int j=0; j<3; j++) {
if(b[j]!='0') {
ip_str[pos] = b[j];
pos++;
}
}
}
// add dot between ip address parts
if(i<3) {
ip_str[pos] = '.';
pos++;
}
}
// add terminator at end of string
ip_str[pos] = '[=11=]';
// print to uart interface
uart_send(ip_str);
// release allocated heap memory
free(ip_str);
}
我在使用不同的 IP 数组进行测试时得到以下结果:
uint8_t[] ip = {192, 168, 0, 99}; => "192.168.0.99" => OK
uint8_t[] ip = {192, 168, 1, 99}; => "192.168.1" => FAILED
uint8_t[] ip = {192, 168, 10, 99}; => "192.168.1" => FAILED
uint8_t[] ip = {10, 10, 10, 10}; => "1" => FAILED
// etc. etc. etc.
我做错了什么?有没有更优雅的方法来完成这个?
就snprintf
吧。
void app_main() {
uint8_t ip[] = {192, 168, 0, 99};
char buf[3 * 4 + 3 * 1 + 1];
snprintf(buf, sizeof(buf), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
uart_send(buf);
}
uint8_t[] ip
无效 C,[]
出现在变量名之后。
sprintf
和snprintf
会将格式化后的字符串打印到第一个参数指向的内存中。
snprintf
将额外的最大尺寸参数作为第二个参数。
- 当传入可变参数列表时,
uint8_t
变量会自动转换为 int
- 因此您可以使用 %d
printf 修饰符打印它们。
- 那么你就有了人类可读的、以 null 结尾的字符串。
最好的答案就是按照 Kamil Cuk 的建议简单地使用 snprintf
。
但是,如果您仍然想知道为什么您的代码不起作用,答案就在这一行:
if(b[j]!='0') {
您只复制了不为零的字符,其中包括空字符。因此,当 IP 的一段包含少于 3 个字符时,您将向字符串中复制一个空值。修复非常简单:
if(b[j]!='[=11=]') {
这让我觉得这很可能只是一个错字!
我目前正在学习 C。我的生态系统包括 Espressif ESP-32 微控制器和 Eclipse CDT IDE。
我正在尝试将 uint8_t[]
转换为人类可读的 IPv4 address string
。到目前为止,我想出了以下代码:
void app_main() {
uint8_t[] ip = {192, 168, 0, 99};
dump_ip(ip);
}
void dump_ip(const uint8_t *in) {
// ip addresses consist of three dots + terminator '[=11=]'
int size = 4;
// count amount of chars needed for specific ip address
for(int i=0; i<4; i++) {
if(in[i]==0) {
size ++;
} else {
size += ((int)log10(in[i]))+1;
}
}
// allocate memory on heap for an ip address of length 'size'
char *ip_str = (char*)malloc(size*sizeof(char));
// copy ip address parts to char array
int pos = 0;
for(int i=0; i<4; i++) {
if(in[i]==0) {
ip_str[pos] = '0';
pos++;
} else {
char b[4];
itoa(in[i], b, 10);
for(int j=0; j<3; j++) {
if(b[j]!='0') {
ip_str[pos] = b[j];
pos++;
}
}
}
// add dot between ip address parts
if(i<3) {
ip_str[pos] = '.';
pos++;
}
}
// add terminator at end of string
ip_str[pos] = '[=11=]';
// print to uart interface
uart_send(ip_str);
// release allocated heap memory
free(ip_str);
}
我在使用不同的 IP 数组进行测试时得到以下结果:
uint8_t[] ip = {192, 168, 0, 99}; => "192.168.0.99" => OK
uint8_t[] ip = {192, 168, 1, 99}; => "192.168.1" => FAILED
uint8_t[] ip = {192, 168, 10, 99}; => "192.168.1" => FAILED
uint8_t[] ip = {10, 10, 10, 10}; => "1" => FAILED
// etc. etc. etc.
我做错了什么?有没有更优雅的方法来完成这个?
就snprintf
吧。
void app_main() {
uint8_t ip[] = {192, 168, 0, 99};
char buf[3 * 4 + 3 * 1 + 1];
snprintf(buf, sizeof(buf), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
uart_send(buf);
}
uint8_t[] ip
无效 C,[]
出现在变量名之后。
sprintf
和snprintf
会将格式化后的字符串打印到第一个参数指向的内存中。snprintf
将额外的最大尺寸参数作为第二个参数。- 当传入可变参数列表时,
uint8_t
变量会自动转换为int
- 因此您可以使用%d
printf 修饰符打印它们。 - 那么你就有了人类可读的、以 null 结尾的字符串。
最好的答案就是按照 Kamil Cuk 的建议简单地使用 snprintf
。
但是,如果您仍然想知道为什么您的代码不起作用,答案就在这一行:
if(b[j]!='0') {
您只复制了不为零的字符,其中包括空字符。因此,当 IP 的一段包含少于 3 个字符时,您将向字符串中复制一个空值。修复非常简单:
if(b[j]!='[=11=]') {
这让我觉得这很可能只是一个错字!