我目前正在学习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 '\0'
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] = '\0';
// 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.
我在做什么错?有没有更优雅的方法可以做到这一点?
答案 0 :(得分:5)
只需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
将格式化的字符串打印到第一个arg指向的内存中。snprintf
采用附加的最大尺寸参数作为第二个参数。uint8_t
变量会自动广播到int
-因此,您可以使用%d
printf修饰符打印它们。答案 1 :(得分:2)
最好的答案就是按照Kamil Cuk的建议使用snprintf
。
但是,如果您仍然想知道为什么代码不起作用,答案就在这一行:
if(b[j]!='0') {
您只复制不为零的字符,其中包括空字符。因此,当IP段中的字符数少于3个时,您将在字符串中复制一个null。修复非常简单:
if(b[j]!='\0') {
这让我认为这很可能只是拼写错误!