I have an array of char and I need to convert it in a ULONGLONG to use it as a MAC address.
My array is like "0X001234567890" but they are all char so if I fit them in my ULONGLONG variable (using unsigned long long cast) they are all messed up.
Is there a way to have those characters in a ULONGLONG format to fit in the address variable?
My char array is formatted as 0 in [0], X in [1], 0 in [2], ecc..
And I build it after reading some values from a file.
char prefixAddr1[30] = "0X";
char prefixAddr2[30] = "0X";
int countAddr = 1;
char addr[30] = "";
char BTaddr1[30] = "";
char BTaddr2[30] = "";
FILE *fpAddress = fopen("BTaddr.txt", "r");
while (fscanf(fpAddress, "%s", &addr) == 1){
unsigned char *r, *w;
for (w = r = addr; *r; r++){
if (*r != ':'){
*w++ = *r;
}
}
*w = '\0';
if (countAddr == 1){
strncpy(BTaddr1, addr, sizeof(addr));
}
else if (countAddr == 2){
strncpy(BTaddr2, addr, sizeof(addr));
}
countAddr++;
}
strcat(prefixAddr1, BTaddr1);
strcat(prefixAddr2, BTaddr2);
printf("Address 1: %s\n", prefixAddr1);
printf("Address 2: %s\n", prefixAddr2);
If I manually set my ULONGLONG variable and print the value with %llu I see the correct address.
typedef ULONGLONG BT_ADDR;
BT_ADDR aSddr1 = 0X001343BD0F65;
printf("Address 1: %llu\n", aSddr1);
I want my char array to have the same value as if I manually set the aSddr1 variable.
From file I read "00:12:34:56:78:90", clear the ":" and append "0X" so my final string is "0X001234567890". Everything in the first example is correct from my point of view. I only need to convert prefixAddr1 in a way that my BT_ADDR variable will be work correctly as in the second example where the output is 0X001234567890. At the moment if I do (unsigned long long)prefixAddr1; and print it I will print some random numbers.
Related
I'm trying to convert the unsigned long integer converted_binary, which contains 10000000000 to a string, but sprintf converts it to a single character 1 instead.
I am able to know this through the vscode debugger.
I expect sprintf to convert the details of converted_binary to a string, but it doesn't. I initially thought the problem was with the malloc, but that doesn't seem to be the case as the problem persists even if manually create a character array large enough.
I've also tried to replace the sprintf with printf to see if something is wrong with the converted_binary variable, but it prints out 10000000000 to stdout normally.
This is the code snippet:
int get_bit(unsigned long int n, unsigned int index)
{
unsigned long int converted_binary, arg_int_len, int_len = 0;
char *converted_string;
int bit;
/*convert n to binary*/
converted_binary = convert(n);
/*convert binary to string*/
arg_int_len = converted_binary;
do
{
arg_int_len = arg_int_len / 10;
++int_len;
}
while (arg_int_len != 0);
converted_string = malloc(sizeof(char *) * int_len);
if (converted_string == NULL)
return (-1);
sprintf(converted_string, "%lu", converted_binary);
/*Loop through string to binary at index*/
bit = (int)converted_string[index];
/*pass that into a variable*/
/*Return the variable*/
return bit;
}
I've the following issue:
from a socket, I receive an hexadecimal string, then I convert it to a byte array and save it into a uint8_t array. Here is the conversion function (it works):
static size_t convert_hex(uint8_t *dest, size_t count, const char *src)
{
size_t i = 0;
int value;
for (i; i < count && sscanf(src + i * 2, "%2x", &value) == 1; i++)
{
dest[i] = value;
}
return i;
}
Then, I reconvert this byte array to an hex string, only to know if the conversion was correct. The conversion is correct beacuse the hexadecimal string received from the socket (before the conversion to a byte array), is the same string after the conversion from uint8_t to hexadecimal string: here is the flow -> HEX_STRING -> UINT8_T ARRAY -> HEX_STRING
static size_t convert_hex_inv(char *dest, size_t count, const uint8_t *src)
{
size_t i = 0;
for (i = 0; i < count && sprintf(dest + i * 2, "%02X", src[i]) == 2; i++)
;
return i;
}
Anyway, when I print the byte array, the result seems stange, because it appears to me too short. Where is the problem? Is it in the print?
n = recvfrom(sockfd, (char *)buffer, 1024,
MSG_WAITALL, ( struct sockaddr *) &cliaddr,
&len);
buffer[n] = '\0';
printf("[SKT]\tHex String: %s. Message Type: %c\n", buffer, buffer[3]);
uint8_t uint8_payload[2048];
uint16_t uint_size = convert_hex(uint8_payload, n, buffer);
printf("[SKT]\tByte Array: %" PRIu8 "\n", uint8_payload);
char hex_array[n];
convert_hex_inv(hex_array, uint_size, uint8_payload);
printf("[SKT]\tHex String: %s\n", hex_array);
}
The result is:
[2021-11-11 12:02:23.410] [SKT] Hex String : 0201000000A8C0000000540000000000000000000000000446E88CEB36E7806FFEFFE000192E5B0F001C029FFFE30101F7D0000C003C000D000401D1C0FF6C3C80
[2021-11-11 12:02:23.410] [SKT] Byte Array: 4152851276 -> **THIS VALUE IS QUITE STRANGE**
[2021-11-11 12:02:23.410] [SKT] Hex String: 0201000000A8C0000000540000000000000000000000000446E88CEB36E7806FFEFFE000192E5B0F001C029FFFE30101F7D0000C003C000D000401D1C0FF6C3C80
With the statement
printf("[SKT]\tByte Array: %" PRIu8 "\n", uint8_payload);
You don't print the contents of the array uint8_payload. Instead you print the pointer to its first element (remember that uint8_payload will decay to &uint8_payload[0]).
To print all the elements you need to do it one by one in a loop.
Writing a program in C and I am trying to pass two variables into the function kstrextend. Name which is a word or set of characters that is stored in the value kstring and a which is a numeric value, but name is not getting passed into the function at all as far as I can tell and I cannot figure out why. Is something not getting stored correctly? Because the function works just fine I just cannot get name passed in correctly.
Declaration of kstring and name:
kstring name;
char kstring[50];
Typedef:
typedef struct
{
char *data;
size_t length;
} kstring;
Function:
void kstrextend(kstring *strp, size_t nbytes)
{
char *nwData;
int lnth=strp->length;
if(lnth < nbytes)
{
// new array allocate with large size and copy data to new array
nwData = (char *)realloc(strp->data, nbytes);
// call abort in case of error
if(nwData == NULL)
{
abort();
}
//Making strp->data point to the new array
strp->data = nwData;
//Setting strp->length to the new size.
strp->length = nbytes;
for(int i = 0; i <= lnth; i++)
{
printf("\n %s",strp->data);
}
// filled with '\0' in remaining space of new array
for (int lp = lnth; lp < nbytes; lp++)
{
strp->data[lp] = '\0';
printf("\n %s", strp->data[lp]);
}
}
}
Portion of main:
size_t a;
char * k = kstring;
printf("\n Enter number: ");
scanf("%d", &a);
name.data = (char*)calloc(sizeof(k), 1);
strcpy(input, k);
name.length= kstring_length;
kstrextend(&name,a);
First of all, you have misleading variable name kstring. Use something else like kstring_init and assign it a value. I assume you want to initialize the name variable of type kstring with something and then change its length. So this is what it is all about. Then define a constant of type char * and initialize length and data of your kstring with it. Then use realloc to extend the memory of the pointer with the input value a, not with the size of k. That does not make sense. Since the size of k is the size of the pointer, which is constant.
In your function: don't use int if you pass size_t. Use the same datatype where you do the same things.
In your loop from 0 to lnth, you output the same string lnth+1 times, which does not make sense. You probably want to output the characters of the string. So use %c and use an index into the character array and don't set <= lnth but < lnth as upper limit. Take care with data types if signed and unsigned!
Design hint: If you have a if block, that wraps all your code... invert the condition and just exit so that the code is after the if block.
Take care when you work with size_t and int, since int is signed and size_t is not, which can give problems in if statements.
Don't use abort but rather exit. You don't want your program to abort abnormally and core-dump.
A working version of your program is:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
char *data;
size_t length;
} kstring;
kstring name;
char *kstring_init = "blabla";
void kstrextend(kstring *strp, size_t nbytes)
{
char *nwData;
size_t lnth = strp->length;
if ((int) lnth >= (int) nbytes) {
printf("Error, size already larger than requested size.\n");
exit(-1);
}
// new array allocate with large size and copy data to new array
nwData = realloc(strp->data, sizeof(char) * (int) nbytes);
if(nwData == NULL)
{
printf("Error, realloc returned NULL\n");
exit(-1);
}
//Making strp->data point to the new array
strp->data = nwData;
//Setting strp->length to the new size.
strp->length = nbytes;
for(int i = 0; i < lnth; i++)
{
printf("\n %c", strp->data[i]);
}
// filled with '\0' in remaining space of new array
for (int lp = lnth; lp < (int) nbytes; lp++)
{
strp->data[lp] = '\0';
printf("\n %c", strp->data[lp]);
}
}
int main(void)
{
size_t a;
printf("\n Enter number: ");
scanf("%d", &a);
name.length = strlen(kstring_init) + 1;
printf("Length of string is: %d\n", name.length);
name.data = (char*)malloc(sizeof(char) * name.length);
strcpy(name.data, kstring_init);
printf("Old string: %s\n", name.data);
printf("You want to reallocate %d bytes\n", a);
kstrextend(&name, a);
return 0;
}
I am trying to convert a substring to integer but I am getting this output
int main()
{
char buf[50] = "210-567-12-2040-34567890.txt";
char* pStart = buf;
char* pCurrent = buf;
while(*pCurrent != '\0')
{
if (*pCurrent == '-' || *pCurrent == '.')
{
uint32_t val = strtoul(pStart, NULL, 10);
pStart = pCurrent+1;
printf("%ul\n",val);
}
++pCurrent;
}
return 0;
}
I am getting this output
210l
567l
12l
2040l
34567890l
Why is there a l in it?
Some of the answers here are what you're looking for: What is the difference between char s[] and char *s?
Short answer is there's no difference between the two as a function argument. You can pass the char* pStart variable into strtoul the same as you'd pass the char str[20] variable into it. This will make it read the string directly from whatever memory address pStart points to, no need to copy into an array first.
Basically I'm writing a printf function for an dedicated system so I want to pass an optional number of arguments without using VA_ARGS macros. I knocked up a simple example and this block of code works:
#include <stdio.h>
void func(int i, ...);
int main(int argc, char *argv);
int main(int argc, char *argv) {
unsigned long long f = 6799000015ULL;
unsigned long long *g;
//g points to f
g = &f;
printf("natural: %llu in hex: %llX address: %x\n", *g, *g, g);
//put pointer onto stack
func(6, g, g);
return 0;
}
void func(int i, ...) {
unsigned long long *f;
//pop value off
f = *(&i + 1);
printf("address: %x natural: %llu in hex: %llX\n", f, *f, *f);
}
However the larger example I'm trying to transfer this to doesn't work.
(in the main function):
unsigned long long f = 6799000015ULL;
unsigned long long *g;
g = &f;
kprintf("ull test: 1=%U 2=%X 3=%x 4= 5=\n", g, g, g);
(my dodgy printf function that I'm having trouble with. It maybe worth pointing out
this code DOES work with ints, char strings or anyother % flags which are passed by
value and not pointer. The only difference between what did work and the unsigned
long longs is one is bigger, so I pass by value instead to ensure I don't increment
the &format+ args part wrongly. Does that make sense?)
void kprintf(char *format, ...)
{
char buffer[KPRINTF_BUFFER_SIZE];
int bpos = 0; /* position to write to in buffer */
int fpos = 0; /* position of char to print in format string */
char ch; /* current character being processed*/
/*
* We have a variable number of paramters so we
* have to increment from the position of the format
* argument.
*/
int arg_offset = 1;
/*
* Think this through Phill. &format = address of format on stack.
* &(format + 1) = address of argument after format on stack.
* void *p = &(format + arg_offset);
* kprintf("xxx %i %s", 32, "hello");
* memory would look like = [ 3, 32, 5, "xxx", 32, "hello" ]
* get to 32 via p = &(format + 1); (int)p (because the int is copied, not a pointer)
* get to hello via p = &(format + 2); (char*)p;
*/
void *arg;
unsigned long long *llu;
arg = (void*) (&format + arg_offset);
llu = (unsigned long long*) *(&format + arg_offset);
while (1)
{
ch = format[fpos++];
if (ch == '\0')
break;
if (ch != '%')
buffer[bpos++] = ch;
else
{
ch = format[fpos++];
if (ch == 's')
bpos += strcpy(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, (char*)arg);
else if (ch == '%')
buffer[bpos++] = '%';
else if (ch == 'i')
bpos += int_to_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
else if (ch == 'x')
bpos += int_to_hex_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
else if (ch == 'o')
bpos += int_to_oct_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *((int*)arg));
else if (ch == 'X') {
//arg is expected to be a pointer we need to further dereference.
bpos += unsigned_long_long_to_hex(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *llu);
} else if (ch == 'U') {
bpos += unsigned_long_long_to_str(&buffer[bpos], KPRINTF_BUFFER_SIZE - bpos, *llu);
} else
{
puts("invalid char ");
putch(ch);
puts(" passed to kprintf\n");
}
arg_offset++;
arg = (void *)(&format + arg_offset);
llu = (unsigned long long*) *(&format + arg_offset);
}
}
buffer[bpos] = '\0';
puts(buffer);
}
(and the unsigned long long functions it goes on to call):
int unsigned_long_long_to_hex(char *buffer, int max_size, unsigned long long number)
{
return ull_number_to_str(buffer, max_size, number, BASE_HEX);
}
int unsigned_long_long_to_str(char *buffer, int max_size, unsigned long long number) {
return ull_number_to_str(buffer, max_size, number, BASE_DECIMAL);
}
int ull_number_to_str(char *buffer, int max_size, unsigned long long number, int base) {
int bufpos = 0;
unsigned int lo_byte = (unsigned int) number;
unsigned int hi_byte = (unsigned int) (number >> 32);
bufpos = number_to_str(buffer, max_size, lo_byte, base);
bufpos += number_to_str(buffer + bufpos, max_size, hi_byte, base);
return bufpos;
}
#define NUMERIC_BUFF_SIZE (11 * (ADDRESS_SIZE / 32))
int number_to_str(char *buffer, int max_size, int number, int base)
{
char *char_map = "0123456789ABCDEF";
int remain = 0;
char buff_stack[NUMERIC_BUFF_SIZE];
int stk_pnt = 0;
int bpos = 0;
/* with this method of parsing, the digits come out backwards */
do
{
if (stk_pnt > NUMERIC_BUFF_SIZE)
{
puts("Number has too many digits to be printed. Increasse NUMBERIC_BUFF_SIZE\n");
return 0;
}
remain = number % base;
number = number / base;
buff_stack[stk_pnt++] = char_map[remain];
} while (number > 0);
/* before writing...ensure we have enough room */
if (stk_pnt > max_size)
{
//error. do something?
puts("number_to_str passed number with too many digits to go into buffer\n");
//printf("error. stk_pnt > max_size (%d > %d)\n", stk_pnt, max_size);
return 0;
}
/* reorder */
while (stk_pnt > 0)
buffer[bpos++] = buff_stack[--stk_pnt];
return bpos;
}
Sorry guys, I can't see what I've done wrong. I appreciate this is a "wall of code" type scenario but hopefully someone can see what I've done wrong. I appreciate you probably dislike not using VA_ARGS but I don't understand why this technique shouldn't just work? And also, I'm linking with -nostdlib too. If someone can help I'd really appreciate it. Also, this isn't meant to be production quality code so if I lack some C fundamentals feel free to be constructive about it :-)
It's a bad idea to code this way. Use stdarg.h.
On the off chance (I presume this based on the name kprintf) that you're working on a hobby kernel or embedded project and looking to avoid using standard libraries, I recommend at least writing your own (architecture and compiler specific) set of stdarg macros that conform to the well-known interfaces and code against that. That way your code doesn't look like such a WTF by dereferencing past the address of the last argument.
You can make a va_list type that stores the last-known address, and your va_arg macro could appropriately align the sizeof of the type it's passed and advance the pointer accordingly. For most conventions I have worked on for x86, every type is promoted to 32 bits...
You have to read on the calling conventions for your platform, i.e. how on your target processor/OS function arguments are passed, and how registers are saved. Not all parameters are passed on stack. Depending on number of parameters and their types, many complex situations can arise.
I should add: if you want to manipulate the stack by hand as you are doing above, you need to do it in assembler, not in C. The C language follows a defined standard, and what you are doing above it not legal code (i.e., its meaning is not well-defined). As such, the compiler is allowed to do anything it wants with it, such as optimize it in weird ways unsuitable to your needs.