i use this part of code to read float value from OSC message on my microcontroller. However i get "dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]" error and no value is showed on printf. Is there any workaround for this one? marker is in struct as:
char *marker; // the current read head
float tosc_getNextFloat(tosc_message *o) {
// convert from big-endian (network btye order)
const uint32_t i = ntohl(*((uint32_t *) o->marker));
o->marker += 4;
return *((float *) (&i)); <---- this line of code does the error
}
EDIT :
So, i recieve data from microcontrollers internet chip over udp using function:
datasize_t recvfrom(uint8_t sn, uint8_t * buf, datasize_t len, uint8_t * addr, uint16_t *port, uint8_t *addrlen) //<- general
then i run another function to parse osc message:
tosc_parseMessage(&A, (char*) buf, received_size); //<- how i wrote parameters
where A is structure:
typedef struct tosc_message {
char *format; // a pointer to the format field
char *marker; // the current read head
char *buffer; // the original message data (also points to the address)
uint32_t len; // length of the buffer data
} tosc_message;
and tosc_parseMessage is:
int tosc_parseMessage(tosc_message *o, char *buffer, const int len) {
// NOTE(mhroth): if there's a comma in the address, that's weird
int i = 0;
while (buffer[i] != '\0') ++i; // find the null-terimated address
while (buffer[i] != ',') ++i; // find the comma which starts the format string
if (i >= len) return -1; // error while looking for format string
// format string is null terminated
o->format = buffer + i + 1; // format starts after comma
while (i < len && buffer[i] != '\0') ++i;
if (i == len) return -2; // format string not null terminated
i = (i + 4) & ~0x3; // advance to the next multiple of 4 after trailing '\0'
o->marker = buffer + i;
o->buffer = buffer;
o->len = len;
return 0;
}
and then i print that out with :
void tosc_printMessage(tosc_message *osc) {
printf("[%i bytes] %s %s",
osc->len, // the number of bytes in the OSC message
tosc_getAddress(osc), // the OSC address string, e.g. "/button1"
tosc_getFormat(osc)); // the OSC format string, e.g. "f"
for (int i = 0; osc->format[i] != '\0'; i++) {
switch (osc->format[i]) {
case 'f': printf(" %g", tosc_getNextFloat(osc)); break;
case 'd': printf(" %g", tosc_getNextDouble(osc)); break;
case 'i': printf(" %d", tosc_getNextInt32(osc)); break;
default: printf(" Unknown format: '%c'", osc->format[i]); break;
}
}
printf("\n");
}
where my problem is in function:
float tosc_getNextFloat(tosc_message *o) {
// convert from big-endian (network btye order)
const uint32_t i = ntohl(*((uint32_t *) o->marker));
o->marker += 4;
return *((float *) (&i)); <---- this line of code does the error
}
I hope this gives you better view on problem... Im not skilled programmer so i appreciate any help. Full code for this "library" could be found here https://github.com/mhroth/tinyosc , Im just trying to implement that in my microcontroller
float tosc_getNextFloat(tosc_message *o) {
// convert from big-endian (network btye order)
const uint32_t i = ntohl(*((uint32_t *) o->marker));
o->marker += 4;
float tmp = 0;
memcpy((void *)&tmp, (void *)&i, sizeof(uint32_t));
return tmp;
}
If type punning is required, it is better to use a compiler that is configured to support it (which on some non-commercially-designed compilers, but not commercially-designed ones, means using -fno-strict-aliasing) than to jump through hoops to accommodate compiler writers that refuse to recognize type punning via pointers that are visibly freshly derived.
C implementations are sometimes used for purposes where type punning is useful, and sometimes for purposes where it isn't. The authors of the Standard recognized that compiler writers should know more about their individual customers' needs than the Committee possibly could, and thus allowed implementations to support whatever combinations of constructs would best fit their customers' needs. Somehow a myth has emerged that Standard characterizes as "broken" programs which relies upon implementations to process them "In a documented fashion characteristic of the environment", but any such reading directly contradicts the stated intentions of the Standard's authors.
After all it wasnt code problem. Yes, i still get that warning ( BUT CODE WORKS ). Actual problem was in IDE. In linker setting inside builder settings this was needed to be added : -u _printf_float . That took like month of my life figuring out what's happening. Thank you all for answering
Related
I'm trying to short the cpu id of my microcontroller (STM32F1).
The cpu id is composed by 3 word ( 3 x 4 bytes). This is the id string built from the 3 word: 980416578761680031125348904
I found a very useful library that do this.
The library is Hashids and there is a C code.
I try to build a test code on PC with "Code Blocks IDE" and the code works.
But when I move the code into the embedded side (Keil v5 IDE), I get an error on strdup() function: "strdup implicit declaration of function".
The problem is related to the strdup function isn't a standard library function and ins't included into string.h.
I will avoid to replace the strdup function with a custom function (that mimic the behaviour of strdup) to avoid memory leak because strdup copy strings using malloc.
Is there a different approach to compress long numbers?
Thanks for the help!
<---Appendix--->
This is the function that uses the strdup.
/* common init */
struct hashids_t *
hashids_init3(const char *salt, size_t min_hash_length, const char *alphabet)
{
struct hashids_t *result;
unsigned int i, j;
size_t len;
char ch, *p;
hashids_errno = HASHIDS_ERROR_OK;
/* allocate the structure */
result = _hashids_alloc(sizeof(struct hashids_t));
if (HASHIDS_UNLIKELY(!result)) {
hashids_errno = HASHIDS_ERROR_ALLOC;
return NULL;
}
/* allocate enough space for the alphabet and its copies */
len = strlen(alphabet) + 1;
result->alphabet = _hashids_alloc(len);
result->alphabet_copy_1 = _hashids_alloc(len);
result->alphabet_copy_2 = _hashids_alloc(len);
if (HASHIDS_UNLIKELY(!result->alphabet || !result->alphabet_copy_1
|| !result->alphabet_copy_2)) {
hashids_free(result);
hashids_errno = HASHIDS_ERROR_ALLOC;
return NULL;
}
/* extract only the unique characters */
result->alphabet[0] = '\0';
for (i = 0, j = 0; i < len; ++i) {
ch = alphabet[i];
if (!strchr(result->alphabet, ch)) {
result->alphabet[j++] = ch;
}
}
result->alphabet[j] = '\0';
/* store alphabet length */
result->alphabet_length = j;
/* check length and whitespace */
if (result->alphabet_length < HASHIDS_MIN_ALPHABET_LENGTH) {
hashids_free(result);
hashids_errno = HASHIDS_ERROR_ALPHABET_LENGTH;
return NULL;
}
if (strchr(result->alphabet, ' ')) {
hashids_free(result);
hashids_errno = HASHIDS_ERROR_ALPHABET_SPACE;
return NULL;
}
/* copy salt */
result->salt = strdup(salt ? salt : HASHIDS_DEFAULT_SALT);
result->salt_length = (unsigned int) strlen(result->salt);
/* allocate enough space for separators */
result->separators = _hashids_alloc((size_t)
(ceil((float)result->alphabet_length / HASHIDS_SEPARATOR_DIVISOR) + 1));
if (HASHIDS_UNLIKELY(!result->separators)) {
hashids_free(result);
hashids_errno = HASHIDS_ERROR_ALLOC;
return NULL;
}
/* non-alphabet characters cannot be separators */
for (i = 0, j = 0; i < strlen(HASHIDS_DEFAULT_SEPARATORS); ++i) {
ch = HASHIDS_DEFAULT_SEPARATORS[i];
if ((p = strchr(result->alphabet, ch))) {
result->separators[j++] = ch;
/* also remove separators from alphabet */
memmove(p, p + 1,
strlen(result->alphabet) - (p - result->alphabet));
}
}
/* store separators length */
result->separators_count = j;
/* subtract separators count from alphabet length */
result->alphabet_length -= result->separators_count;
/* shuffle the separators */
hashids_shuffle(result->separators, result->separators_count,
result->salt, result->salt_length);
/* check if we have any/enough separators */
if (!result->separators_count
|| (((float)result->alphabet_length / (float)result->separators_count)
> HASHIDS_SEPARATOR_DIVISOR)) {
unsigned int separators_count = (unsigned int)ceil(
(float)result->alphabet_length / HASHIDS_SEPARATOR_DIVISOR);
if (separators_count == 1) {
separators_count = 2;
}
if (separators_count > result->separators_count) {
/* we need more separators - get some from alphabet */
int diff = separators_count - result->separators_count;
strncat(result->separators, result->alphabet, diff);
memmove(result->alphabet, result->alphabet + diff,
result->alphabet_length - diff + 1);
result->separators_count += diff;
result->alphabet_length -= diff;
} else {
/* we have more than enough - truncate */
result->separators[separators_count] = '\0';
result->separators_count = separators_count;
}
}
/* shuffle alphabet */
hashids_shuffle(result->alphabet, result->alphabet_length,
result->salt, result->salt_length);
/* allocate guards */
result->guards_count = (unsigned int) ceil((float)result->alphabet_length
/ HASHIDS_GUARD_DIVISOR);
result->guards = _hashids_alloc(result->guards_count + 1);
if (HASHIDS_UNLIKELY(!result->guards)) {
hashids_free(result);
hashids_errno = HASHIDS_ERROR_ALLOC;
return NULL;
}
if (HASHIDS_UNLIKELY(result->alphabet_length < 3)) {
/* take some from separators */
strncpy(result->guards, result->separators, result->guards_count);
memmove(result->separators, result->separators + result->guards_count,
result->separators_count - result->guards_count + 1);
result->separators_count -= result->guards_count;
} else {
/* take them from alphabet */
strncpy(result->guards, result->alphabet, result->guards_count);
memmove(result->alphabet, result->alphabet + result->guards_count,
result->alphabet_length - result->guards_count + 1);
result->alphabet_length -= result->guards_count;
}
/* set min hash length */
result->min_hash_length = min_hash_length;
/* return result happily */
return result;
}
The true question seems to be
Is there a different approach to compress long numbers?
There are many. They differ in several respects, including which bits of the input contribute to the output, how many inputs map to the same output, and what manner of transformations of the input leave the output unchanged.
As a trivial examples, you can compress the input to a single bit by any of these approaches:
Choose the lowest-order bit of the input
Choose the highest-order bit of the input
The output is always 1
etc
Or you can compress to 7 bits by using using the number of 1 bits in the input as the output.
None of those particular options is likely to be of interest to you, of course.
Perhaps you would be more interested in producing 32-bit outputs for your 96-bit inputs. Do note that in that case on average there will be at least 264 possible inputs that map to each possible output. That depends only on the sizes of input and output, not on any details of the conversion.
For example, suppose that you have
uint32_t *cpuid = ...;
pointing to the hardware CPU ID. You can produce a 32-bit value from it that depends on all the bits of the input simply by doing this:
uint32_t cpuid32 = cpuid[0] ^ cpuid[1] ^ cpuid[2];
Whether that would suit your purpose depends on how you intend to use it.
You can easily implement strdup yourself like this:
char* strdup (const char* str)
{
size_t size = strlen(str);
char* result = malloc(size);
if(result != NULL)
{
memcpy(result, str, size+1);
}
return result;
}
That being said, using malloc or strdup on an embedded system is most likely just nonsense practice, see this. Nor would you use float numbers. Overall, that library seems to have been written by a desktop-minded person.
If you are implementing something like for example a chained hash table on an embedded system, you would use a statically allocated memory pool and not malloc. I'd probably go with a non-chained one for that reason (upon duplicates, pick next free spot in the buffer).
Unique device ID register (96 bits) is located under address 0x1FFFF7E8. It is factory programmed and is read-only. You can read it directly without using any other external library. For example:
unsigned int b = *(0x1FFFF7E8);
should give you the first 32 bits (31:0) of the unique device ID. If you want to retrieve a string as in case of the library mentioned, the following should work:
sprintf(id, "%08X%08X%08X", *(0x1FFFF7E8), *(0x1FFFF7E8 + 4), *(0x1FFFF7E8 + 8);
Some additional casting may be required, but generally that's what the library did. Please refer to STM32F1xx Reference Manual (RM0008), section 30.2 for more details. The exact memory location to read from is different in case of Cortex-M4 family of the MCUs.
Most of the times, the questions I ask have to do with a specific part of a code that i did incorrectly, or some bug that i overlooked, but this time, I don't know where to start. I don't even know if what I am trying to do is possible.
I was given an assignment to write a code that gets a string that resembles a variable declaration, for example int x,y; is a valid input. char c,*cptr,carray[80]; is another example of valid input.
The code will create what the user inputs, and will print how much memory it took.
For instance, in the first example (int x,y;) the code will create 2 integers, and print "x requires 4 bytes, y requires 4 bytes".
In the second example, the code will create a character, a pointer to a character, and a string with 80 characters, and will print "c requires 1 byte, cptr requires 4 bytes, carray requires 80 bytes"
Is this even possible? It is not valid code to declare variables after the beginning of the code. They must be declared before anything else in C. So I don't see a way to do this...
This is a parsing problem -- you need to parse the input string and figure out what it means. You don't need to actually "create" anything, you just need to figure out the sizes of the variables that the compiler would create for that code.
Parsing actually a very large subject, with lots of books written about it and tools written to make it easier. While you could use a tool like antlr or bison to complete this task, they're probably overkill -- a simple recursive descent hand-written parser is probably the best approach.
Something like:
const char *parse_declaration(const char *p) {
/* parse a declaration, printing out the names and sizes of the variables
* 'p' points at the beginning of the string containing the declaration, and the
* function returns the pointer immediately after the end or NULL on failure */
int size;
if (!(p = parse_declspecs(p, &size))) return 0;
do {
const char *name;
int namelen, declsize;
if (!(p = parse_declarator(p, size, &name, &namelen, &declsize))) return 0;
printf("%.*s requires %d bytes\n", namelen, name, declsize);
p += strspn(p, " \t\r\n"); /* skip whitespace */
} while (*p++ == ',');
if (p[-1] != ';') return 0;
return p;
}
const char *parse_declspecs(const char *p, int *size) {
/* parse declaration specifiers (a type), and output the size of that type
* p points at the string to be parsed, and we return the point after the declspec */
p += strspn(p, " \t\r\n");
if (!isalpha(*p)) return 0;
int len = 0;
while (isalnum(p[len])) len++;
if (!strncmp(p, "char", len)) {
*size = sizeof(char);
return p+len; }
if (!strncmp(p, "int", len)) {
*size = sizeof(int);
return p+len; }
... more type tests here ...
if (!strncmp(p, "unsigned", len)) {
p += len;
p += strspn(p, " \t\r\n");
if (!isalpha(*p)) {
*size = sizeof(unsigned);
return p; }
while (isalnum(p[len])) len++;
if (!strncmp(p, "int", len)) {
*size = sizeof(unsigned int);
return p+len; }
... more type tests here ...
}
return 0;
}
const char *parse_declarator(const char *p, int typesize, const char **name, int *namelen, int *declsize) {
/* parse a declarator */
p += strspn(p, " \t\r\n");
while (*p == '*') {
typesize = sizeof(void *); /* assuming all pointers are the same size...*/
p++;
p += strspn(p, " \t\r\n"); }
declsize = typesize;
if (isalpha(*p)) {
*name = p;
while (isalnum(*p) | *p == '_') p++;
*namelen = p - *name;
} else if (*p == '(') {
if (!(p = parse_declarator(p+1, typesize, name, namelen, declsize))) return 0;
p += strspn(p, " \t\r\n");
if (*p++ != ')') return 0;
} else
return 0;
p += strspn(p, " \t\r\n");
while (*p == '[') {
int arraysize, len;
if (sscanf(++p, "%d %n", &arraysize, &len) < 1) return 0;
p += len;
declsize *= arraysize;
if (*p++ != ']') return 0;
p += strspn(p, " \t\r\n"); }
return p;
}
should get you started...
If you are trying to execute input code dynamically, to my knowledge that would not be possible without storing the code and then compiling again. This however seems like a very nasty and lengthy approach. If all you are trying to do however is calculate the size of declarations from input, what I would do is take the string received, call a function that analyzes/decomposes the string. So for example if the string has "int", "char", etc.. I know would know what kind of declaration I am dealing with, and after I know what declaration I am dealing with I could just count the number of variables declared and keep a counter in your example it was x,y. I would a loop on the counter and calculate the sizeof the type of declaration and how many were declared.
Sure, it's possible; it's just a bit of work. You're going to have to study C declaration syntax, and then write the code to recognize it (basically a small compiler front end).
For example, in the declaration
char c, *cptr, carray[80];
you have a sequence of tokens:
char c , * cptr , carray [ 80 ] ;
which will be recognized as a type specifier (char) followed by three declarators; a direct declarator, a pointer declarator, and an array declarator.
You can create the space for the objects dynamically using malloc or calloc. Then you'll need to create some kind of table to map the identifier (the variable name) to the dynamically-created object. You won't be able to treat these things as regular variables in regular C code; you're going to be doing a lot of table lookups and dereferencing.
Sure, you could do this with a type of parser. Assuming that you do not want to actually execute the code that you are given, you could read the string and then count how many times a variable of each specific type is declared, and calculate the amount of memory thusly. But, depending on the requirements of the professor, you may run into a view different issues.
In particular, the sizes of different types will likely be different on each processor. With the exception of char, you need to account for this. This is easy if you are analyzing the memory requirements for the computer that your program is executing on, as you could just have const variables whose values are assigned via sizeof to get the sizes, but if not, your program is more difficult, especially since you cannot presume to know the size of any variable.
Secondly, structs will be a problem do to some of the more interesting rules of C. Do you need to account for them?
So, this is entirely possible, because contrary to what you stated in your question, your code doesn't have to "create" a variable at all - it can just create an in-memory total for each type and print them out when done.
Figured I would post my solution just incase anyone is interested
void* q5(char* str_in)
{
char runner;
int i=0,memory,counter=0,arr_size;
runner=str_in[i];
while(1)
{
if(runner=='i') //the input is integer
{
memory=sizeof(int);
break;
}
if(runner=='c') //input is char
{
memory=sizeof(char);
break;
}
if(runner=='d') //input is double
{
memory=sizeof(double);
break;
}
if(runner=='s') //input is short
{
memory=sizeof(short);
break;
}
if(runner=='l') //input is long
{
memory=sizeof(long);
break;
}
if(runner=='f') //input is float
{
memory=sizeof(float);
break;
}
} //we know the type of data, skip in the string until first variable
while(runner!=' ') //advance until you see empty space, signaling next variable
{
i++;
runner=str_in[i];
}
while(runner==' ') //advance until you encounter first letter of new variable
{
i++;
runner=str_in[i];
} //runner is now first letter of first variable
while(runner!=';') //run on the string until its over
{
if(runner==',') //if its ',', then spaces will occur, skip all of them to first char that isnt space
{
i++;
runner=str_in[i];
while(runner==' ')
{
i++;
runner=str_in[i];
} //runner now points to first letter of variable
continue;
}
if(runner=='*') //current variable is a pointer
{
counter=counter+4; //pointers are always 4 bytes regardless of type!
i++;
runner=str_in[i];
while((runner!=',')&&(runner!=';')) //while runner is still on this variable
{
printf("%c",runner);
i++;
runner=str_in[i];
}
printf(" requires 4 bytes\n"); //now runner is the first character after the variable we just finished
continue;
}
while((runner!=',')&&(runner!=';')) //now is the case that runner is the first letter of a non pointer variable
{
printf("%c",runner);
i++;
runner=str_in[i];
if((runner==',')||(runner==';')) //we are done
{
printf(" requires %d bytes\n",memory);
counter+=memory;
continue;
}
if(runner=='[') //this variable is an array
{
printf("[");
i++;
runner=str_in[i]; //runner is now MSB of size of array
arr_size=0;
while(runner!=']')
{
printf("%c",runner);
arr_size*=10;
arr_size=arr_size+runner-48; //48 is ascii of 0
i++;
runner=str_in[i];
} //arr_size is now whats written in the [ ]
printf("] requires %d bytes\n",arr_size*memory);
counter+=arr_size*memory;
i++;
runner=str_in[i]; // should be ',' since we just finished a variable
continue;
}
}
}
printf("Overall %d bytes needed to allocate\n",counter);
return (malloc(counter));
}
A while back I asked this question.
I eventually hacked together a sort of solution:
int convertWindowsSIDToString(void *sidToConvert, int size, char* result) {
const char *sidStringPrefix = "S-";
int i;
int concatLength = 0;
/* For Linux I have SID defined in a seperate header */
SID *sid;
char revision[2], identifierAuthority[2];
if(sidToConvert == NULL) {
return 1;
}
sid = (SID *)sidToConvert;
snprintf(revision, 2, "%d", sid -> Revision);
snprintf(identifierAuthority, 2, "%d", sid -> IdentifierAuthority.Value[5]);
/* Push prefix in to result buffer */
strcpy (result,sidStringPrefix);
/* Add revision so now should be S-{revision} */
strcat(result, revision);
/* Append another - symbol */
strcat(result, "-");
/* Add the identifier authority */
strcat(result, identifierAuthority);
/* Sub Authorities are all stored as unsigned long so a little conversion is required */
for (i = 0; i < sid -> SubAuthorityCount; i++) {
if(concatLength > 0){
concatLength += snprintf(result + concatLength, size, "-%lu", sid -> SubAuthority[i]);
} else {
concatLength = snprintf(result, size, "%s-%lu", result, sid -> SubAuthority[i]);
}
}
return 0;
}
I'm a complete amateur at C.
In the few test cases I have run, this works fine but I am worried about how I'm handling strings here.
Is there any better way to handle string concatenation in this type of scenario? Please note, I am kind of tied to C89 compatibility as I am trying to keep all code compiling on all platforms and am stuck with Visual Studio on Windows for now.
Also my apologies if this question is not the best format for Stack Overflow. I guess I'm asking more for a code review that a very specific question but not sure where else to go.
EDIT
Just wanted to add what I think is almost the final solution, based on suggestions here, before accepting an answer.
int convertWindowsSIDToString(SID *sidToConvert, int size, char* result) {
int i;
char* t;
if(sidToConvert == NULL) {
printf("Error: SID to convert is null.\n");
return 1;
}
if(size < 32) {
printf("Error: Buffer size must be at least 32.\n");
return 1;
}
t = result;
t+= snprintf(t, size, "S-%d-%d", sidToConvert->Revision, sidToConvert->IdentifierAuthority.Value[5]);
for (i = 0; i < sidToConvert -> SubAuthorityCount; i++) {
t += snprintf(t, size - strlen(result), "-%lu", sidToConvert -> SubAuthority[i]);
}
return 0;
}
I've got a lot of reading to do yet by the look of things. Got to admit, C is pretty fun though.
If you know that the result buffer will be bin enough (which you usually can ensure by allocating the maximum space necessary for any of the formats and validating your inputs before formatting them), you can do something like the following:
char* buffer = malloc(BIG_ENOUGH);
char* t = buffer;
t+=sprintf(t, "%d", sid->Revision);
t+=sprintf(t, "%d", sid->IdentifierAuthority.Value[5]);
for (i = 0; i < sid -> SubAuthorityCount; i++) {
t += sprintf(t, "-%lu", sid -> SubAuthority[i]);
}
printf("Result: %s\n", buffer);
Looks all to complicated to me. I'd replace most of it with a single snprintf()
So this...
snprintf(revision, 2, "%d", sid -> Revision);
snprintf(identifierAuthority, 2, "%d", sid -> IdentifierAuthority.Value[5]);
/* Push prefix in to result buffer */
strcpy (result,sidStringPrefix);
/* Add revision so now should be S-{revision} */
strcat(result, revision);
/* Append another - symbol */
strcat(result, "-");
/* Add the identifier authority */
strcat(result, identifierAuthority);
...would become
snprintf("S-%d-%d", size, sid->Revision, sid->IdentifierAuthority.Value[5]);
Also, in your loop, you're not using size correctly.
concatLength += snprintf(result + concatLength, size, "-%lu", sid -> SubAuthority[i]);
You should use size-concatLength so that the size reflects how much has already been written.
Oh, and this:-
concatLength = snprintf(result, size, "%s-%lu", result, sid -> SubAuthority[i]);
.. is probably unsafe, as your destination is one of your source parameters. Generally, for the loop I;d use a solution like #MagnusReftel's.
I have a network capture tool that captures packets and does some processing on them. Now, here is a small fragment of the code. u_char is the name given to unsigned char. When I try to print the variable smac to stdout, all I get is 000000000000 on the screen. I want to print the actual smac and dmac.
char * str;
char converted[6*2 + 1];
u_char smac[6], dmac[6];
int i;
if (ntop_lua_check(vm, __FUNCTION__, id, LUA_TSTRING))
return(CONST_LUA_PARAM_ERROR);
if ((str = (char*)lua_tostring(vm, id)) == NULL)
return(CONST_LUA_PARAM_ERROR);
sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&smac[0], &smac[1], &smac[2], &smac[3], &smac[4], &smac[5]);
for (i = 0; i < 6; i++)
{
sprintf(&converted[i*2], "%02X", smac[i]);
}
printf("%s\n", converted);
Is the problem with unsigned char getting promoted to int or something by sprintf and printing the unnecessary two bytes? I am not sure.Any help would be of great value. Thank you.
I am currently having exceptional difficulty with CUDA programming--more specifically, in copying and reading an array which the device sends back to the host. When I attempt to read the data which I am supposed to have returned to me, all I get is junk data. Could anyone take a look at my code snippets and tell me what I'm doing wrong? Thank you very much!
struct intss {
u_int32_t one;
u_int32_t two;
};
int main()
{
int block_size = 3;
int grid_size = 1;
intss *device_fb = 0;
intss *host_fb = 0;
int num_bytes_fb = (block_size*grid_size)*sizeof(intss);
host_fb = (intss*)malloc(num_bytes_fb);
cudaMalloc((void **)&device_fb, num_bytes_fb);
....
render2<<<block_size,grid_size>>>(device_fb, device_pixelspercore, samples, obj_list_flat_dev, numOpsPerCore, lnumdev, camdev, lightsdev, uranddev, iranddev);
....
cudaMemcpy(host_fb, device_fb, num_bytes_fb, cudaMemcpyDeviceToHost);
printf("output %d ", host_fb[0].one);
printf("output %d ", host_fb[1].one);
printf("output %d ", host_fb[2].one);
//Note that I'm only looking at elements the 3 elements 0-2 from host_fb. I am doing this because block_size*grid_size = 3. Is this wrong?
cudaFree(device_fb);
free(host_fb);
}
__global__ void render2(intss *device_fb, struct parallelPixels *pixelsPerCore, int samples, double *obj_list_flat_dev, int numOpsPerCore, int lnumdev, struct camera camdev, struct vec3 *lightsdev, struct vec3 *uranddev, int *iranddev) //SPECIFY ARGUMENTS!!!
{
int index = blockIdx.x * blockDim.x + threadIdx.x; //DETERMINING INDEX BASED ON WHICH THREAD IS CURRENTLY RUNNING
....
//computing data...
device_fb[index].one = (((u_int32_t)(MIN(r, 1.0) * 255.0) & 0xff) << RSHIFT |
((u_int32_t)(MIN(g, 1.0) * 255.0) & 0xff) << GSHIFT |
((u_int32_t)(MIN(b, 1.0) * 255.0) & 0xff) << BSHIFT);
}
EDIT:
Thanks to a suggestion, I have implemented the CudaErrorCheck function in my program, and there seems to be a pattern in which functions are giving me errors.
In my program, I have a bunch of global host arrays(obj_list, lights, urand, irand). Whenever I attempt to use cudaMemCpy to copy these host arrays to device arrays, I receive the following error:
"Cuda error in file 'cudatrace.cu' in line x : invalid argument."
obj_list and lights are filled in the following function, load_scene():
void load_scene(FILE *fp) {
char line[256], *ptr, type;
obj_list = (sphere *)malloc(sizeof(struct sphere));
obj_list->next = 0;
objCounter = 0;
while((ptr = fgets(line, 256, fp))) {
int i;
struct vec3 pos, col;
double rad, spow, refl;
while(*ptr == ' ' || *ptr == '\t') ptr++;
if(*ptr == '#' || *ptr == '\n') continue;
if(!(ptr = strtok(line, DELIM))) continue;
type = *ptr;
for(i=0; i<3; i++) {
if(!(ptr = strtok(0, DELIM))) break;
*((double*)&pos.x + i) = atof(ptr);
}
if(type == 'l') {
lights[lnum++] = pos;
continue;
}
if(!(ptr = strtok(0, DELIM))) continue;
rad = atof(ptr);
for(i=0; i<3; i++) {
if(!(ptr = strtok(0, DELIM))) break;
*((double*)&col.x + i) = atof(ptr);
}
if(type == 'c') {
cam.pos = pos;
cam.targ = col;
cam.fov = rad;
continue;
}
if(!(ptr = strtok(0, DELIM))) continue;
spow = atof(ptr);
if(!(ptr = strtok(0, DELIM))) continue;
refl = atof(ptr);
if(type == 's') {
objCounter++;
struct sphere *sph = (sphere *)malloc(sizeof(*sph));
sph->next = obj_list->next;
obj_list->next = sph;
sph->pos = pos;
sph->rad = rad;
sph->mat.col = col;
sph->mat.spow = spow;
sph->mat.refl = refl;
} else {
fprintf(stderr, "unknown type: %c\n", type);
}
}
}
urand and irand are filled in main as follows:
/* initialize the random number tables for the jitter */
for(i=0; i<NRAN; i++) urand[i].x = (double)rand() / RAND_MAX - 0.5;
for(i=0; i<NRAN; i++) urand[i].y = (double)rand() / RAND_MAX - 0.5;
for(i=0; i<NRAN; i++) irand[i] = (int)(NRAN * ((double)rand() / RAND_MAX));
I don't think the invalid argument could be caused by the device array, since the cudaMalloc call creating the device array before the cudaMemcpy call did not have a CudaError message. For example, in the following lines of code:
cudaErrorCheck(cudaMalloc((void **)&lightsdev, MAX_LIGHTS*sizeof(struct vec3)) );
cudaErrorCheck( cudaMemcpy(&lightsdev, &lights, sizeof(struct vec3) * MAX_LIGHTS, cudaMemcpyHostToDevice) );
cudaMalloc did not produce an error, but cudaMemcpy did.
If I have not provided enough information on my code, I have pasted the entire code to: http://pastebin.com/UgzABPgH
(Note that in the pastebin version, I took out the CudaErrorCheck functions on the CudaMemcpy's which were producing the errors.)
Thank you very much!
EDIT:
Actually, I just tried to see what would happen if urand and irand were not global, and if they were initialized alongside the device arrays uranddev and iranddev. I'm still getting the same "invalid argument" error, so the whether or not a variable is global must not relate to the problem.
It is absolutely impossible to say anything when you have posted incomplete, uncompilable code with no proper description of the actual problem. You will get better answers by asking better questions on StackOverflow.
Having said that. the most likely problem isn't that the data is not being copied to or from the device, it is that the kernel itself is not running. Every CUDA runtime API call returns a status code, and you should be checking all of them. You can define an error checking macro like this one:
#include <stdio.h>
#define cudaErrorCheck(call) { cudaAssert(call,__FILE__,__LINE__) }
void cudaAssert(const cudaError err, const char *file, const int line)
{
if( cudaSuccess != err) {
fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n",
file, line, cudaGetErrorString(err) );
exit(1);
}
}
and wrap every API call in it, like this:
cudaErrorCheck( cudaMemcpy(host_fb, device_fb, num_bytes_fb, cudaMemcpyDeviceToHost) );
For the kernel launch, itself you can check for a launch failure or runtime error like this:
kernel<<<....>>>();
cudaErrorCheck( cudaPeekAtLastError() ); // Checks for launch error
cudaErrorCheck( cudaThreadSynchronize() ); // Checks for execution error
My suggestion is add thorough error checking to your code and then come back and edit your question with the results you get. Then someone might be able to offer concrete suggestions about what is happening.
I think you're not using the <<< >>> syntax correctly.
Here's a kernel invocation from the CUDA Programming Guide:
MatAdd<<<numBlocks, threadsPerBlock>>>(A, B, C);
which would mean that the grid size should go first.
There's also a limitation on the maximum size for the arguments to a kernel. See this. If you go above it, I'm not sure whether the compiler complains or just goes on to do nasty things.
If I remove all the arguments but device_fb, and just set device_fb[index]=index in the kernel, I can read the values successfully.