What's the best/recommended way to copy data between a byte array and an integer in C? Currently I'm using memcpy, which doesn't feel right to me. A sample of the sort of thing I'm doing is below.
struct alpha {
unsigned char byte_array[20];
}
void function(struct alpha *st) {
unsigned long num;
/* Do some stuff */
memcpy(st->byte_array, &num, sizeof(unsigned long));
/* Do more stuff */
memcpy(&num, st->byte_array, sizeof(unsigned long));
}
I assume I want to use casts somehow, but I'm not confident of how casting and pointer (de)referencing interacts, particularly when arrays get involved.
memcpy is the standard and portable tool for that effect. Modern optimized compilers will inline this call to something well adapted to your situation, e.g data types, allignement, size (if known at compile time), processor... So I think you should definitively stick to that and not mess around with some handmade optimizations.
It looks exactly the right way to me. Which is to say, when I had to do this, it was the way I did it.
Here's how to do it with casts:
/* Do some stuff */
*(unsigned long *)st = num;
/* Do more stuff */
num = *(unsigned long *)st;
You're casting your struct pointer to a pointer to an unsigned long, then dereferencing the pointer in the assignment statements.
It is not wrong, unless you know that "who" wrote the data into the array wrote them in an endianness different from the one used on your system. Say, e.g., if those data come from a "stream" sent by "someone" over the net. Then, if the protocol uses the so called "network byte order" (namely big endian), and your machine is not big endian, then you obtain wrong values.
Is there any particular reason you need to copy instead of just aliasing the two? e.g.:
union XXX {
char byte_array[20];
unsigned long num;
};
In theory, you don't get defined results when you write to one member of the union then read from the other member. In reality, there's essentially no possibility of getting anything different from what you're getting now -- except (of course) that you don't have to copy data to get from one view to the other -- you just use x.num to look at it as an unsigned long, and x.byte_array to look at it as an array of bytes.
memcpy is the safest way to do this sort of thing. If speed matters though, you can do some cast magic to let the compiler handle the copy natively for you:
*((unsigned long *)&st->byte_array[0]) = num;
num = *((unsigned long *)&st->byte_array[0]);
Both these will use built in register type copies instead of a function call of 4 bytes. If you want to read further into the byte_array, you must be careful of byte alignment issues with this though.
I prefer some default functions for this requirement,
for string to integer
int atoi ( const char * str );
and
for integer to string
char * itoa ( int value, char * str, int base );
#include <stdio.h>
#include <stdlib.h>
int main()
{
unsigned long int number;
unsigned char string[256];
printf ("Enter a number: ");
fgets ( string, 256, stdin );
number = atoi (string);
printf("number = %d\n",number);
//converting int to string
itoa (number,string,10); //10 is base here for decimal, 16 is used for Hex and 2 for Binary
printf ("string = %s\n",string);
return 0;
}
as per me atoi() function is fine. But in case you don't want to use itoa() or it is not available to you then you can just use sprintf()
sprintf (string,"%ld",number);
I hope it helps
Thanks
Alok.kr.
Related
I have a char array that holds a memory address for example
char add[8]="000AAC88";
I want to put a character into the memory address specified by the add array , in other words I want to have a character for example 'a' in the memory address of 000AAC88
This will be done in C
You can use strtoull() with a base of 16 or sscanf() to convert from a hexadecimal number in ASCII to a wide-enough integer, and then convert that to a pointer. Here, I use strtoull() for simplicity.
If your library implements it in a way that works for you, you might also use the %p format specifier to convert directly between pointers and their string representation.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define HEX_DIGITS_IN_PTR (sizeof(unsigned long long int)*2U)
int main(void)
{
static const char msg[] = "hello, world!\n";
char hex_address[HEX_DIGITS_IN_PTR] = {'\0'};
snprintf( hex_address,
sizeof(hex_address),
"%llX",
(unsigned long long int)(uintptr_t)(void*)&msg );
const char* const converted_ptr =
(void*)(uintptr_t)strtoull( hex_address, NULL, 16 );
fputs( converted_ptr, stdout );
return EXIT_SUCCESS;
}
Once you’ve converted to a char*, you can do pointer arithmetic on it.
Your assumption that 8 hex digits are enough to hold a pointer will break in 64-bit code. In this example, for brevity, I assume that an unsigned long long int is wide enough to store any pointer. However, if you want to be as portable and future-proof as possible, you can use the constants in <inttypes.h> with sscanf(). Alternatively, POSIX (and Linux) also provide width-restricted environments that guarantee that an unsigned long is wide enough to hold a pointer.
You can use sscanf to load the address to pointer.
char *p;
sscanf(add, "%08X", &p);
*p = 'a';
Check the usage of sscanf here
I'm making PE file format analyzer in C language.
When I used Visual Studio, I could make it much easier.
BUT, I have tired to make it without Visual Studio to improve my C programing.
It was made by GCC(My laptop is macbook).
To analyze PE file format, as you know I have to use file pointer and read file as 'rb' type.
I did it and it looks like worked well.... I wanted to print first and second words("MZ") but It printed unkown(to me) numbers.
P.S I write little different code refer to previous one to smaller than before. But It print NULL.
It means that I wrote code really wrong... PLZ tell me which parts are wrong
#include <stdio.h>
#include <stdlib.h>
// struct to save info of PE_File format
typedef struct _IMAGE_DOS_HEADER
{
unsigned short e_magic;
unsigned short e_cblp;
unsigned short e_cp;
unsigned short e_crlc;
unsigned short e_cparhdr;
unsigned short e_minalloc;
unsigned short e_maxalloc;
unsigned short e_ss;
unsigned short e_sp;
unsigned short e_csum;
unsigned short e_ip;
unsigned short e_cs;
unsigned short e_lfarlc;
unsigned short e_ovno;
unsigned short e_res[4];
unsigned short e_oemid;
unsigned short e_oeminfo;
unsigned short e_res2[10];
unsigned long e_lfanew;
} DOS_HEADER;
// I use two different functions.
// First one was made to import PE File format info from file that I used.
// Another was made to print some imformation. I use some comment because I didn't realize those.
DOS_HEADER get_dos_header(FILE *fp, char* fp_buffer);
void print_data_of_structures(DOS_HEADER/*, NT_HEADER, FILE_HEADER, OPTIONAL_HEADER, DATA_DIRECTORY*/);
int main(void)
{
DOS_HEADER dos_header;
char file_path[1000];
printf("Please input your file path : ");
scanf("%[^\n]s", file_path);
FILE* fp = NULL;
fp = fopen(file_path, "rb");
if(fp == NULL)
printf("Unalbe to open file :/\n");
// To calculate file size.
long fp_size = 0;
fseek(fp, 0, SEEK_END);
fp_size = ftell(fp);
rewind(fp);
// Declare to use as buffer
char* fp_buffer = malloc(sizeof(char) * (fp_size + 1));
// Use function to save analyzed information.
DOS_HEADER info_dos_header = get_dos_header(fp, fp_buffer);
// Print information.
print_data_of_structures(info_dos_header);
fclose(fp);
free(fp_buffer);
return 0;
}
DOS_HEADER get_dos_header(FILE* fp, char* fp_buffer)
{
DOS_HEADER raw_info_dos_header = {0, };
// Read hex info from fp 2 byte 1 time and save at fp_buffer.
fseek(fp, 0, SEEK_SET);
fread(fp_buffer, 2, 1, fp);
raw_info_dos_header.e_magic = fp_buffer;
return raw_info_dos_header;
}
void print_data_of_structures(DOS_HEADER info_dos_header/*, NT_HEADER info_nt_header, FILE_HEADER info_file_header, OPTIONAL_HEADER info_optional_header, DATA_DIRECTORY info_data_directory*/)
{
// print info_dos_header
printf("Print DOS_HEADER\n");
// I tried several print format(for example %hu, %x, %d) But I coudn't "MZ" or any numbers has realation with "MZ".
printf("%s", info_dos_header.e_magic);
}
You have 2 big problems with your code: you are mixing types.
In DOS_HEADER all members (except the last one) are of type unsigned short.
That's important.
In get_dos_header you are doing
fread(fp_buffer, 2, 1, fp);
raw_info_dos_header.e_magic = fp_buffer;
which is wrong.
Don't use magic numbers, use sizeof to get the correct sizes
Check the return value of fread, specially if you are analyzing a binary
format, you must be sure that you've read exactly what you're expecting.
It's much easier to deal with fread when the size argument is 1, because
only when the size argument is 1 the return value of fread matches the
number of bytes read.
e_magic is a unsigned short, fp_buffer is a char*. This assignment is
not copying the contents pointed to by fp_buffer, you are storing an address
as if it were a unsigned short value. You need to copy the memory pointed to
by fp_buffer.
Also I don't see the point of you allocating a buffer of the size of the file
when you are reading chunk by chunk. It would be easier if you don't allocate a
buffer at all and use an array of a size larger than what you are going to read.
int get_dos_header(FILE* fp, DOS_HEADER *dos)
{
unsigned char buffer[8];
size_t ret = fread(buffer, 1, sizeof(dos->e_magic), fp);
if(ret != sizeof(dos->e_magic))
{
fprintf(stderr, "Invalid file size\n");
return 0;
}
memcpy(&dos->e_magic, buffer, sizeof(dos->e_magic));
// DO the others fread operation
...
return 1;
}
Then in main you can do this:
DOS_HEADER raw_info_dos_header = {0, };
if(get_dos_header(fp, &raw_info_dos_header) == 0)
{
fprintf(stderr, "failed to get the DOS header\n");
return 1;
}
...
The second problem is in print_data_of_structures:
printf("%s", info_dos_header.e_magic);
e_magic is a unsigned short, %s expects a pointer to char, it expects a
string. e_magic is definitively not a string. This yield undefined behaviour.
The printf should look like this:
printf("e_magic: %hu\n", info_dos_header.e_magic);
or
printf("e_magic: 0x%04hx\n", info_dos_header.e_magic);
to print it in hexadecimal format.
I also advice you to use pointers instead. Your struct is big and passing a
pointer to a function is much cheaper than passing a copy of a large struct to a
functions. So instead of
void print_data_of_structures(DOS_HEADER info_dos_header);
declare it as
void print_data_of_structures(DOS_HEADER *info_dos_header);
And also don't declare function that can fail (like get_dos_header) as
void, otherwise how do you tell the calling function that it failed? It's
better for such functions to return an int (1 for success, 0 for failure) and
expect a pointer to the struct where the information is stored (see how I
changed get_dos_header above.
I been working in a project for my Data Networks class and they ask me to concatenate a header like this:
struct ip
{
unsigned long a;
unsigned long b;
unsigned int l;
} IP;
And a message which it's a char* let's say "Hello".
So, I use this method to concatenate those two in a single char*:
memcpy(sendBuf, (void*)&sendHeader, sizeof(sendHeader));
memcpy(&sendBuf[sizeof(sendHeader)], readMessage, lengthMessage);
With lengthMessage being the number of characters of the message +1 which is the null termination character.
So, sendBuf it's defined like this:
char sendBuf[BUFLEN + 1] // BUF_LEN = 128
And then I put this char* in a queue defined like this:
concurrency::concurrent_queue<char*> IP_in_queue;
So, I want to check if the information it's correct, so I just check everything:
char* s;
IP_in_queue.try_pop(s);
numbytes = sizeof(s);
// Copy from buf to the header
memcpy( (void*)&readHeader, s, sizeof( IP_PACKET_HEADER_T));
// Copy message part
memcpy( sendedString, &s[sizeof(IP_PACKET_HEADER_T)], numbytes - sizeof(IP_PACKET_HEADER_T));
// Append \0 to the end
sendedString[numbytes - sizeof(IP_PACKET_HEADER_T)] = '\0';
So, before I queue my char*, we know that the size of sendBuf is 129, but when I check the number of bytes after I dequeue it's way too different, the value of number of bytes it's 4, but even in that way I get the information right, so I don't understand that, maybe I missing some important things, but the variable numbytes shouldn't be at least more?
I hope I made myself clear and maybe someone can explain me this a little bit better.
Thanks
sizeof does not tell you the length of the string - it tells you the size of the type char*, which on a 32-bit machine is 4 bytes. You want strlen, the number of bytes in the string.
But even that isn't what you want. Your structure IP can have nulls in it, so even strlen won't give you a correct answer. If you put your string first instead of last you can fix that, but I'd consider that kind of a hack. You should add the size explicitly to the start of your message.
My structure looks as follows:
typedef struct {
unsigned long attr;
char fileName[128];
} entity;
Then I try to assign some values but get an error message...
int attribute = 100;
char* fileNameDir = "blabla....etc";
entity* aEntity;
aEntity->attr = attributes;
aEntity->fileName = fileNameDir;
Compiler tells me:
Error: #137: expression must be a modifiable lvalue
aEntity->fileName = fileNameDir;
Why cant I assign here this character to the one in the structure?
Thanks
You're treating a char[] (and a char*, FTM) as if it was a string. Which is is not. You can't assign to an array, you'll have to copy the values. Also, the length of 128 for file names seems arbitrary and might be a potential source for buffer overflows. What's wrong with using std::string? That gets your rid of all these problems.
You're defining a pointer to some entity, don't initialize it, and then use it as if at the random address it points to was a valid entity object.
There's no need to typedef a struct in C++, as, unlike to C, in C++ struct names live in the same name space as other names.
If you absolutely must use the struct as it is defined in your question (it is pre-defined), then look at the other answers and get yourself "The C Programming Language". Otherwise, you might want to use this code:
struct entity {
unsigned long attr;
std::string fileName;
};
entity aEntity;
aEntity.attr = 100;
aEntity.filename = "blabla....etc";
You can't assign a pointer to an array. Use strncpy() for copying the string:
strncpy( aEntity->fileName, fileNameDir, 128 );
This will leave the destination not null-terminated if the source is longer than 128. I think the best solution is to have a bigger-by-one buffer, copy only N bytes and set the N+1th byte to zero:
#define BufferLength 128
typedef struct {
unsigned long attr;
char fileName[BufferLength + 1];
} entity;
strncpy( aEntity->FileName, fileNameDir, BufferLength );
*( aEntity->FileName + BufferLength ) = 0;
You should be copying the filename string, not changing where it points to.
Are you writing C or C++? There is no language called C/C++ and the answer to your question differs depending on the language you are using. If you are using C++, you should use std::string rather than plain old C strings.
There is a major problem in your code which I did not see other posters address:
entity* aEntity;
declares aEntity (should be anEntity) as a pointer to an entity but it is not initialized. Therefore, like all uninitialized pointers, it points to garbage. Hence:
aEntity->attr = attributes;
invokes undefined behavior.
Now, given a properly initialized anEntity, anEntity->fileName is an array, not a pointer to a character array (see question 6.2 in the C FAQ list). As such, you need to copy over the character string pointed to by fileNameDir to the memory block reserved for anEntity->fileName.
I see a lot of recommendations to use strncpy. I am not a proponent of thinking of strncpy as a safer replacement for strcpy because it really isn't. See also Why is strncpy insecure?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct st_entity {
unsigned long attr;
char fileName[FILENAME_MAX + 1];
} entity;
int main(void) {
int status = EXIT_FAILURE;
unsigned long attribute = 100;
char *fileNameDir = "blabla....etc";
entity *anEntity = malloc(sizeof(*anEntity));
if ( anEntity ) {
anEntity->attr = attribute;
anEntity->fileName[0] = '\0';
strncat(anEntity->fileName, fileNameDir, sizeof(anEntity->fileName) - 1);
printf("%lu\n%s\n", anEntity->attr, anEntity->fileName);
status = EXIT_SUCCESS;
}
else {
fputs("Memory allocation failed", stderr);
}
return status;
}
See strncat.
You're trying to use char* as if it was a string, which it is not. In particular, you're telling the compiler to set filename, a 128-sized char array, to the memory address pointed by fileNameDir.
Use strcpy: http://cplusplus.com/reference/clibrary/cstring/strcpy/
You can't assign a pointer to char to a char array, they're not compatible that way, you need to copy contents from one to another, strcpy, strncpy...
Use strncpy():
strncpy( aEntity->fileName, fileNameDir, sizeof(entity.fileName) );
aEntity.fileName[ sizeof(entity.fileName) - 1 ] = 0;
The strncpy() function is similar,
except that not more than n bytes of
src are copied. Thus, if there is no
null byte among the first n bytes of
src, the result will not be
null-terminated. See man page.
1) The line char* fileNameDir = "blabla....etc" creates a pointer to char and assigns the pointer an address; the address in this case being the address of the text "blabla....etc" residing in memory.
2) Furthermore, arrays (char fileName[128]) cannot be assigned to at all; you can only assign to members of an array (e.g. array[0] = blah).
Knowing (1) and (2) above, it should be obvious that assigning an address to an array is not a valid thing to do for several reasons.
What you must do instead is to copy the data that fileNameDir points to, to the array (i.e. the members of the array), using for example strncpy.
Also note that you have merely allocated a pointer to your struct, but no memory to hold the struct data itself!
First of all, is this supposed to be C or C++? The two are not the same or freely interchangeable, and the "right" answer will be different for each.
If this is C, then be aware you cannot assign strings to arrays using the '=' operator; you must either use strcpy() or strncpy():
/**
* In your snippet above, you're just declaring a pointer to entity but not
* allocating it; is that just an oversight?
*/
entity *aEntity = malloc(sizeof *aEntity);
...
strcpy(aEntity->fileName, fileNameDir);
or
strncpy(aEntity->fileName, fileNameDir, sizeof aEntity->fileName);
with appropriate checks for a terminating nul character.
If this is C++, you should be using the std::string type for instead of char* or char[]. That way, you can assign string data using the '=' operator:
struct entity {unsigned long attr; std::string fileName};
entity *aEntity = new entity;
std::string fileNameDir = "...";
...
entity->fileName = fileNameDir;
The major problem is that you declared a pointer to a struct, but allocated no space to it (unless you left some critical code out). And the other problems which others have noted.
The problem lies in the fact that you cannot just use a pointer without initialising it to a variable of that same datatype, which in this is a entity variable. Without this, the pointer will point to some random memory location containing some garbage values. You will get segmentation faults when trying to play with such pointers.
The second thing to be noted is that you can't directly assign strings to variables with the assignment operator(=). You have to use the strcpy() function which is in the string.h header file.
The output of the code is:
100 blabla......etc
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
unsigned long attr;
char fileName[128];
} entity;
void main()
{
unsigned long int attribute = 100;
char *fileNameDir = "blabla....etc";
entity struct_entity;
entity *aEntity = &struct_entity;
aEntity->attr = attribute;
strcpy(aEntity->fileName, fileNameDir);
printf("%ld %s", struct_entity.attr, struct_entity.fileName);
}
For char fileName[128], fileName is the array which is 128 char long. you canot change the fileName.
You can change the content of the memory that filename is pointing by using strncpy( aEntity->fileName, fileNameDir, 128 );
Using c, I have defined a byte and word as follows:
typedef unsigned char byte;
typedef union {
byte b[4];
unsigned long w;
} word;
This allows me to easy go from words to bytes, but I'm not sure of a good way to go the other way. Is it possible to do something like cast from byte* to word* or do I have to stick with iteratively copying bytes to words?
One of the great and terrible things about c is you can take a void pointer and cast it to anything. As long as you know what you are doing it will work, but not something you want to get in the habit of.
const byte input[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
unsigned long output[sizeof(input) / sizeof(unsigned long)];
memcpy(output, input, sizeof(input));