Preceding zeros are ignored - c

I am modifying airodump-ng to build a custom application.
I need the output in this format
{AP Mac 1, Station Mac 1},{AP Mac 2, Station Mac 2},...............
To do this I traverse through struct ST_INFO and using multiple strcat calls I generate an array in the above format.
The problem arises when the MAC address contains preceding zeros and this results in data corruption
eg: 0A1B23443311 is saved as A1B23443311
eg: 001B3311ff22 is saved as 1B3311ff22 ( The 0s have been ignored)
What should I do so that data is saved properly when MAC address contains preceding zeros?
The final array is written to a file.
Update: Printing leading 0's in C?
When I tried to print the MAC address the results were the same as given in the above examples but when I used %02x (I learned about it from above link) the problem was solved when I want to print.
Since, I want to save the contents to an array, is there any trick like the %02x for printf.
The struct ST_INFO contains unsigned char st_mac[6] (MAC address is stored in hex format) and my final array is also unsigned char array.

There are multiple ways to do, but if you're using snprintf() or one of its relatives, the %02x (or maybe %02X, or %.2x or %.2X) formats will be useful. For example:
const unsigned char *st_mac = st_info_struct.st_mac;
unsigned char buffer[13];
for (int i = 0; i < 6; i++)
sprintf(&buffer[2*i], "%.2X", st_mac[i]);
(Usually, using snprintf() is a good idea; here, it is unnecessary overkill, though it would not be wrong.)
You should not be using multiple strcat() calls to build up the string. That leads to a quadratic algorithm. If the strings are long (say kilobytes or more), this begins to matter. You also shouldn't be using strcat() because you need to know how long everything is (the string you've created so far, and the string you're adding to it) so that you can ensure you don't overflow your storage space.

if there is a fixed length for all the addresses, just check the length before appending it. If the
length < fixed_length , append difference between the length's number of zeroes.

Related

Printing out values of a struct byte by byte

Basically, I'm trying to cast a char array to a pointer to a struct and print out the values in the struct byte by byte. This is because some legacy code I'm dealing with uses a macro to do some bitwise shifting and masking to change 4 bits within an integer in a struct, and I'm trying to find out whether the macro is working as intended. However, I've compressed my problem to this toy example-
#include <stdio.h>
#include <stdint.h>
int main()
{
struct student
{
int32_t hi;
int8_t test
};
struct student p1 = {20, 20};
for(int i = 0; i < sizeof(p1); i++)
{
printf("%c",((char*)&p1)[i]);
}
return 0;
}
For some reason, this prints out two characters (that show up as boxes with 0014 in them) and nothing else. If I change the for loop to go from 0 to 5 (which is roughly the bounds of the for loop that I'm expecting) I get the exact same output. Is there a way to do what I want (i.e. get this to print out 5 characters)? I know that some of the characters will just be empty spaces, but I don't understand how I'm not getting said empty spaces.
You're trying to print binary values as characters. How those characters get printed depends on your console, but byte values of 0 typically don't print anything.
If you want to see what the values of the bytes are, print them as hex numbers instead:
printf("%02x ",((char*)&p1)[i]);
Read more about ASCII. Some characters are control characters so are not shown nicely, and your system might have some weird character encoding. Be aware than in 2019, UTF-8 is used everywhere (almost).
You'll better print your bytes in hexadecimal:
printf("%02x",(unsigned int) ((char*)&p1)[i]);
and you might have an implementation with signed char -s, so it could be better to replace char* with an explicit unsigned char* (or even better uint8_t* from <stdint.h>). Notice that it is documented that printf with %02x wants an unsigned integer (not simply a char). Anything else could be undefined behavior.
Refer at least to some C reference site, and consider looking into the C11 standard n1570.
Of course, enable all warnings and debug info in your compiler (with GCC, compile with gcc -Wall -Wextra -g) and use the debugger (e.g. use gdb). So read How to debug small programs.

Changing char* string in a C loop

I am trying to change a string within a loop to be able to save my images with a changing variable. Code snippet is as follows:
for (frames=1; frames<=10; frames++)
{
char* Filename = "NEWIMAGE";
int Save_Img = is_SaveImageMemEx (hCam, Filename, pMem, memID,
IS_IMG_PNG, 100);
printf("Status Save %d\n",Save_Img);
}
What I want to do is put a variable that changes with the loop counter inside Filename so my saved file changes name with every iteration.
Any help would be great.
Create a file name string with sprintf and use the %d format conversion specifier for an int:
char filename[32];
sprintf(filename, "NEWIMAGE-%d", frames);
sprintf works just like printf, but "prints" to a string instead of stdout.
If you declared frames as an unsigned int, use %u. If it is a size_t use %zu. For details see your friendly printf manual page, which will tell you how you can for example zero pad the number.
Be sure that the character array you write to is large enough to hold the longest output plus an extra '\0' character. In your particular case NEWIMAGE-10 + 1 means 11 + 1 = 12 characters is enough, but 32 is future-proof for some time.
If you want to program like a pro, look at the snprintf and asnprintf functions, which can limit or allocate the memory written to, respectively.
You can use sprintf to create a formatting string:
char Filename[50];
sprintf(Filename, "NEWIMAGE%d", frames);

printing the hex values after storing it to an array using C

I have done the reading from a file and is stored as hex values(say the first value be D4 C3). This is then stored to a buffer of char datatype. But whenever i print the buffer i am getting a value likebuff[0]=ffffffD4; buff[1]=ffffffC3 and so on.
How can I store the actual value to the buffer without any added bytes?
Attaching the snippet along with this
ic= (char *)malloc(1);
temp = ic;
int i=0;
char buff[1000];
while ((c = fgetc(pFile)) != EOF)
{
printf("%x",c);
ic++;
buff[i]=c;
i++;
}
printf("\n\nNo. of bytes written: %d", i);
ic = temp;
int k;
printf("\nBuffer value is : ");
for(k=0;k<i;k++)
{
printf("%x",buff[k]);
}
The problem is a combination of two things:
First is that when you pass a smaller type to a variable argument function like printf it's converted to an int, which might include sign extension.
The second is that the format "%x" you are using expects the corresponding argument to be an unsigned int and treat it as such
If you want to print a hexadecimal character, then use the prefix hh, as in "%hhx".
See e.g. this printf (and family) reference for more information.
Finally, if you only want to treat the data you read as binary data, then you should consider using int8_t (or possibly uint8_t) for the buffer. On any platform with 8-bit char they are the same, but gives more information to the reader of the code (saying "this is binary data and not a string").
By default, char is signed on many platforms (standards doesn't dictate its signedness). When passing to variable argument list, standard expansions like char -> int are invoked. If char is unsigned, 0xd3 remains integer 0xd3. If char is signed, 0xd3 becomes 0xffffffd3 (for 32-bit integer) because this is the same integer value -45.
NB if you weren't aware of this, you should recheck the entire program, because such errors are very subtle. I've dealed once with a tool which properly worked only with forced -funsigned-char into make's CFLAGS. OTOH this flag, if available to you, could be a quick-and-dirty solution to this issue (but I suggest avoiding it for any longer appoaching).
The approach I'm constantly using is passing to printf()-like functions a value not c, but 0xff & c, it's visually easy to understand and stable for multiple versions. You can consider using hh modifier (UPD: as #JoachimPileborg have already suggested) but I'm unsure it's supported in all real C flavors, including MS and embedded ones. (MSDN doesn't list it at all.)
You did store the actual values in the buffer without the added bytes. You're just outputting the signed numbers with more digits. It's like you have "-1" in your buffer but you're outputting it as "-01". The value is the same, it's just you're choosing to sign extend it in the output code.

How to store CHAR array to string MAC ADDRESS

I have a function that returns a unsigned char chMAC[6]; which is the mac address and i print it out as
printf("Mac: %x",chMAC[0]);
printf("%x",chMAC[1]);
printf("%x",chMAC[2]);
printf("%x",chMAC[3]);
printf("%x",chMAC[4]);
printf("%x\n",chMAC[5]);
And i get an output as Mac: B827E82D398E which is the actual mac address, but now i need to get that value as a string to pass to a sql parameter and i don't know how, since i need to add : in between. such as Mac: B8:27:E8:2D:39:8E
i bet this is easy, but i am still learning C.
You probably want all the bytes to be displayed as two characters:
%2x
but with a leading 0 instead of space:
%02x
You can string this all together in one printf call
printf("Mac: %02X:%02X:%02X:%02X:%02X:%02X\n"
, chMAC[0], chMAC[1], chMAC[2], chMAC[3], chMAC[4], chMAC[5]);
If you want the text to go to a sting buffer instead of stdout do this:
char buffer[32];
snprintf(buffer, sizeof(buffer)
, "Mac: %02X:%02X:%02X:%02X:%02X:%02X\n"
, chMAC[0], chMAC[1], chMAC[2], chMAC[3], chMAC[4], chMAC[5]);
You have all the pieces there, you just need to string them into the right order. Instead of using 6 separate printf() statements, pull it into one statement with all the formatting:
printf("Mac: %02X:%02X:%02X:%02X:%02X:%02X\n",
chMAC[0], chMAC[1], chMAC[2], chMAC[3], chMAC[4], chMAC[5]);
The "02" in the "%02X" formatting statements will put a leading zero if the value is <15; the capital X will make the alphabetic Hex digits into capitals (which is the usual convention when passing MAC addresses).
To send the resulting string to a buffer instead of to stdout, call sprintf (or even better, snprintf) with the same formatting string.
char mac_str[24];
snprintf(mac_str, sizeof(mac_str), "Mac: %02X:%02X:%02X:%02X:%02X:%02X\n",
chMAC[0], chMAC[1], chMAC[2], chMAC[3], chMAC[4], chMAC[5]);
why all the separate calls?
newlength = sprintf(mac, '%x:%x:%x:%x:%x:%x\n', chMAC[1], etc....)
You can have multiple %whatever format characters in a single printf/sprintf call...

C - formatting MAC address

I am currently working with parsing some MAC addresses. I am given an output that does not include leading zeros (like so).
char* host = "0:25:25:0:25:25";
and I would like to format it like so
char* host = "00:25:25:00:25:25";
What would be the easiest way to go about this?
For those wondering, I am using the libpcap library.
I may be missing something in the question. Assuming you know it is a valid MAC, and the input string is thus parsable, have you considered something as simple as:
char* host1 = "0:25:25:0:AB:25";
char *host2 = "0:1:02:3:0a:B";
char result[19];
int a,b,c,d,e,f;
// the question sample
if (sscanf(host1, "%x:%x:%x:%x:%x:%x", &a,&b,&c,&d,&e, &f) == 6)
sprintf(result, "%02X:%02X:%02X:%02X:%02X:%02X", a,b,c,d,e,f);
printf("host1: %s\n", result);
// a more daunting sample
if (sscanf(host2, "%x:%x:%x:%x:%x:%x", &a,&b,&c,&d,&e, &f) == 6)
sprintf(result, "%02X:%02X:%02X:%02X:%02X:%02X", a,b,c,d,e,f);
printf("host2: %s\n", result);
Output
host1: 00:25:25:00:AB:25
host2: 00:01:02:03:0A:0B
Obviously for the ultra-paranoid you would want to make sure a-f are all < 255, which is probably preferable. The fundamental reasons I prefer this where performance isn't a critical issue are the many things you may not be considering in your question. It handles all of
Lead values of "n:", where n is any hex digit; not just zero. Examples: "5:", "0:"
Mid values of ":n:", again under the same conditions as (1) above. Examples: ":A:", ":0:"
Tail values of ":n". once more, under the same conditions as (1) above. Examples: ":b", ":0"
Hex-digit agnostic when reading; it works with both upper and lower case digit chars.
Most important, does nothing (except upper-case the hex values) if your input string is already properly formatted.
Roughly like this:
Allocate an output string to hold the reformatted MAC address.
Iterate over the input string and use strtok with : delimiter. In each iteration convert the beginning of the string (2 bytes) into a numerical value (e.g., with atoi). If the result < 16 (i.e., < 0x10), set "0" into the output string at current position and the result in hex at the following position; otherwise copy the 2 bytes of input string. Append : to the output string. Continue till end of the input.

Resources