简体   繁体   English

在C中将char转换为unsigned short

[英]Converting char to unsigned short in C

I've been having some trouble saving char values into a structure field which is of the type unsigned short . 我在将char值保存到unsigned short类型的结构字段时遇到了一些麻烦。

---EDIT: Here's the input .pgm --- ---编辑:这是输入.pgm-

P2
6 10

255

255 255 255 255 10 255

255 255 255 255 20 255

255 255 255 255 30 255

255 255 255 255 40 255

255 255 255 255 50 255

255 255 255 255 60 255

110 255 255 255 70 255

255 100 90 80 255 255

255 255 255 255 255 255

255 255 255 255 255 255

So we're suppose to save a matrix composed of 0's and 1's, or other numbers. 因此,我们假设要保存一个由0和1或其他数字组成的矩阵。 The structures are as follows: 结构如下:

typedef struct{
    unsigned short rgb[3];   
}PIXEL_T;

typedef struct{
    int format;
    int nrows;
    int ncolumns;
    int max_color;
    PIXEL_T **pixels;   
}PBM_T;

And here's the code to save the 1 or 0 chars into the appropriate structure field. 这是将1或0个字符保存到适当的结构字段中的代码。

void pbmMatrixASCII(char* line, size_t len, FILE* file_stream, PBM_T *img_struct) {

    int i = 0, j = 0;
        char *token;

    while(getline(&line, &len, file_stream) != EOF) {
        token = strtok(line, " \n\t");
        while (token != NULL) {
            //DEBUG("%s", token);
            img_struct->pixels[i][j].rgb[0] = strtol(token, NULL, 0);
            token = strtok(NULL, " \n\t");
            printf("%hu ", img_struct->pixels[i][j].rgb[0]);
            j++;
        }
        printf("\n");   
        i++;
    }
}

Now this works great for 0's and 1's. 现在,这非常适合0和1。 Problem is, when we have to save a matrix which has values ranging from 1 to 255. It saves and prints garbage. 问题是,当我们必须保存一个值在1到255之间的矩阵时,它会保存并打印垃圾。 And we tried several casting methods. 我们尝试了几种铸造方法。 For example: 例如:

img_struct->pixels[i][j].rgb[0] = (unsigned short) token;

They don't work. 他们不工作。 How can we fix this? 我们该如何解决? (Also, is there a PROPER way to actually convert the values, one that serves for both problems?) (此外,是否存在一种正确的方法来实际转换值,这同时解决了两个问题?)

----EDIT in response to some feedback---- ----编辑以回应一些反馈意见----

We're reading from pbm and pgm files. 我们正在读取pbm和pgm文件。 The second line of which is the size of the matrix, which we then read to the img_struct->nrows and img_struct->ncolumns . 第二行是矩阵的大小,然后我们将其读取为img_struct->nrowsimg_struct->ncolumns Here's the code: 这是代码:

//Detects the filetype and reads the matrix size (also reads max color in case of pgm)

//Reads the first line to determine the magic number    

    getline(&line, &len, file_stream);
    sscanf(line, "P%d", &aux_format);

    //Verifies if the format is valid. Exits if not

    if(aux_format > 6 || aux_format < 1) {
        ERROR(ERR_FORMAT,"Invalid format\n");
    }

    img_struct->format = aux_format; //Saves the format into the structure, after being verified

    int size_is_read = 0; //Variable used to verify if the size has been read (a makeshift boolean)

        while(getline(&line, &len, file_stream) != EOF){

            if (hasCommentsOrEmptyLines(line))
                continue;

    //Reads the size of the matrix

            if(size_is_read == 0) {
                sscanf(line,"%d %d",&columns,&rows);
                size_is_read = 1;
            }

            if(img_struct->format == 1 || img_struct->format == 4) { //P1 and P4 are .pbm files and therefore don't have  a maximum colour field
                break;

            } else if(img_struct->format == 2 || img_struct->format == 5){ //Every other file type needs to have its maximum colour field read

                while(getline(&line, &len, file_stream) != EOF) {

                    if(hasCommentsOrEmptyLines(line))
                        continue;

    //reads the max color                   
                    sscanf(line,"%d",&(img_struct->max_color));

                break;
            }

        }
        break;
    }

And after that, the memory alloc followed by the matrix reader function call (see above): 然后,进行内存分配,然后调用矩阵读取器函数(请参见上文):

//Save the image size in the appropriate structure fields   
img_struct->nrows = rows;
img_struct->ncolumns = columns;

//Allocates the appropriate size of the matrix to save the bitmap

img_struct->pixels = MALLOC(sizeof(PIXEL_T *)*rows);
if (img_struct->pixels == NULL)
    ERROR(ERR_ALLOC,"Error allocating memory for the bitmap matrix");

for(i = 0; i < rows; i++) {
    img_struct->pixels[i] = MALLOC(sizeof(PIXEL_T)*columns);
}


//Iterate each position of the line array and convert it to an unsigned short 

switch(img_struct->format) {

    case 1:
        pbmMatrixASCII(line, len, file_stream, img_struct);
    break;

    case 2:
        printf("teste\n");
        pgmMatrixASCII(line, len, file_stream, img_struct);
    break;

So in your file format you have : row = 6 column = 10 因此,在您的文件格式中,您有:行= 6列= 10

The content is : 内容是:

RGBRGB RGBRGB

RGBRGB RGBRGB

.

.

.

The row value is not the number of pixels but the number of pixels * 3. So 2 pixels per row. 行值不是像素数,而是像素数*3。因此,每行2个像素。

You store your pixel data as : Pixel_t **data; 您将像素数据存储为: Pixel_t **data; -> pointer of a pointer of a structure containing a static array of 3 unsigned shorts. ->包含3个无符号短裤的静态数组的结构的指针。

You allocate the data that way : 您可以这样分配数据:

data = malloc(sizeof(Pixel_t*) * row);

so now data is an array of pointers of pixel_t of size 'row' 所以现在数据是大小为'row'的pixel_t指针数组

then you allocate each pointer of pixel_t : data[n] = malloc(sizeof(pixel_t) * column); 然后您分配pixel_t的每个指针:data [n] = malloc(sizeof(pixel_t)* column); so now for each row you basically have an array of size of 3 unsigned short * columns which makes it 3 times too big because you allocate a pixel for each column. 因此,现在每行基本上都有一个数组,该数组的大小为3个无符号的短*列,这使其变得太大了3倍,因为您为每列分配了一个像素。

When you loop through your data you always write to : 当您遍历数据时,您始终会写入:

data[y][x].rgb[0]

which is exactly like : 就像:

*(data[y][x])

which makes your structure useless because every-time you access to the first element of your array... So depending after how you output your data, you will have garbage at the end of you array because you never actually use it since it's 3 times too big. 这使您的结构无用,因为每次您访问数组的第一个元素时...因此,根据输出数据的方式,您将在数组末尾产生垃圾,因为您从未实际使用它,因为它是3次太大。

Also using strtok and strtol and store it to a unsigned short is supposed to work fine in your case so the parsing is not the problem. 同样,在您的情况下,使用strtok和strtol并将其存储到unsigned short中也可以正常工作,因此解析不是问题。

#include <string.h>
#include <stdio.h>

int main()
{
    char *str = strdup("255 42 25 255 67 89\n");
    char *token = strtok(str, " \n");
    while (token)
    {
        unsigned short val = strtol(token, 0, 0);
        token = strtok(0, " \n");
        printf("%hu\n", val);
    }

    return 0;
}

This code outputs the correct data. 此代码输出正确的数据。

Instead of using C functions for tokenizing the string, try simply iterating through it like so: 与其使用C函数来标记字符串,不如尝试简单地遍历它,如下所示:

void pbmMatrixASCII(char* line, size_t len, FILE* file_stream, PBM_T *img_struct) {
    int i = 0;

    while(getline(&line, &len, file_stream) != EOF) {
        // Extract all pixel entries.
        int nFound = getPixels(line, img_struct->ncolumns, img_struct->pixels[i]);

        // Print out what we found.
        // int j = 0;
        // for (j = 0; j < nFound; j++) {
        //     printf("%hu %s",
        //         img_struct->pixels[i][j].rgb[0],
        //         ((j + 1) == nFound ? "\n": ""));
        // }

        // Go to the next row of pixels if we found values.
        if (nFound == img_struct->ncolumns)
            i++;
    }
}

And have another function parse each line you read in: 并具有另一个函数来解析您读入的每一行:

int getPixels(char * line, int numExpected, PIXEL_T * pixelRow) {
    int max                = strlen(line);
    int counter            = 0;
    PIXEL_T * currentPixel = pixelRow;
    char * linePtr         = line;

    while (counter < numExpected) {
        // Reach the first non-whitespace character.
        while (linePtr[0] == ' ') {
            if ((linePtr - line) >= max)
                return (counter);

            linePtr++;
        }

        if (linePtr[0] == '\n')
            return (counter);

        // Grab the unsigned short value.
        int numFound = sscanf(linePtr, "%hu", &currentPixel->rgb[0]);

        // Make sure we found something.
        if (numFound > 0)
            currentPixel++, counter++;
        // Error happened with sscanf! Return what we found so far.
        else if (numFound < 0)
            return (counter);

        // Reach the first non-NON-whitespace character. Double negative ;)
        while (linePtr[0] != ' ') {
            if ((linePtr - line) >= max)
                return (counter);

            linePtr++;
        }
    }
    return (counter);
}

This way, you never have to actually cast the value from a character; 这样,您就不必实际从字符中转换值了。 it's read as an unsigned short by sscanf(...). sscanf(...)将其读取为无符号的短型。

-- EDIT: The following is for reading from PPM files -- -编辑:以下内容用于读取PPM文件-

Note: numExpected is the number of expected RGB triplets you'll see. 注意: numExpected是您将看到的预期RGB 三元组的数量。 Passing in a value of 2 means there should be 2 pixels there, each with 3 values, totaling to 6 actual entries on the line read in. This corresponds to the width value in the top part of the PPM file, itself. 传递2的值表示那里应该有2个像素,每个像素3个值,总计读入行中的6个实际条目。这对应于PPM文件本身顶部的宽度值。

int getPixels(char * line, int numExpected, PIXEL_T * pixelRow) {
    int max                = strlen(line);
    int counter            = 0;
    int currentValue       = 0;
    PIXEL_T * currentPixel = pixelRow;
    char * linePtr         = line;

    while (counter < numExpected) {
        while (currentValue < 3) {
            // Reach the first non-whitespace character.
            while (linePtr[0] == ' ') {
                if ((linePtr - line) >= max)
                    return (counter);

                linePtr++;
            }

            if (linePtr[0] == '\n') {
                return (counter);
            }

            // Grab the unsigned short value.
            int numFound = sscanf(linePtr, "%hu", &currentPixel->rgb[currentValue]);

            // Make sure we found something.
            if (numFound == 1)
                currentValue++;

            // Error happened with sscanf! Return what we found so far.
            else if (numFound < 0)
                return (counter);

            // Reach the first non-NON-whitespace character. Double negative ;)
            while (linePtr[0] != ' ') {
                if ((linePtr - line) >= max)
                    return (currentValue == 3 ? counter + 1 : counter);

                linePtr++;
            }
        }

        counter++, currentPixel++, currentValue = 0;
    }
    return (counter);
}

Sorry, i cant post a comment, just an answer. 抱歉,我无法发表评论,只能提供答案。 Have you ever tried to use a debugger?? 您是否曾经尝试过使用调试器? Its made for this purpose. 它是为此目的而制成的。 You can step through every line of code and watch the current data of your variables. 您可以遍历代码的每一行,并查看变量的当前数据。 See whats happening when you read 0/1 and again when you read other values. 读取0/1时查看发生了什么,读取其他值时再次查看。 Then you can exactly locate the error. 然后,您可以准确定位错误。

mfg MFG

Just modified your read-function a bit and tried it on my on: 只是稍微修改了您的读取功能,然后在我的设备上尝试了一下:

static const char filename[] = "ok.pgm";
FILE *file = fopen ( filename, "r" );

while(fgets(line, sizeof line, file) != NULL) {
    token = strtok(line, " \n\t");

    while(token != NULL) {
        //DEBUG("%s", token);
        long int t = strtol(token, NULL, 0);
        token = strtok(NULL, " \n\t");
        printf("%hu ", t);
        j++;
    }
    printf("\n");
    i++;
}

Output: 输出:

0
6 10
255
255 255 255 255 10 255
255 255 255 255 20 255
255 255 255 255 30 255
255 255 255 255 40 255
255 255 255 255 50 255
255 255 255 255 60 255
110 255 255 255 70 255
255 100 90 80 255 255
255 255 255 255 255 255
255 255 255 255 255 255

Process returned 0 (0x0)   execution time : 0.016 s
Press any key to continue.

Writing it to an unsigned short provides the same output. 将其写入无符号的short可以提供相同的输出。 It seems you have a problem with your struct... 看来您的结构有问题...

BTW: Code is bad, just an example if the reading works. 顺便说一句:代码不好,如果阅读有效,请举一个例子。

In the code line: 在代码行中:

img_struct->pixels[i][j].rgb[0] = (unsigned short) token;

You are assigning token which is a pointer to unsigned short. 您正在分配令牌,它是指向无符号short的指针。 When you cast it you transform pointer to unsigned int. 强制转换时,将指针转换为unsigned int。 That may looks like a garbage. 那看起来像是垃圾。 You can fix it in the following way: 您可以通过以下方式修复它:

unsigned int value = (unsigned int)atoi(token);
img_struct->pixels[i][j].rgb[0] = value;

In the snippet below loop counter j is always incremented. 在下面的代码段中,循环计数器j始终递增。 Thus when reading second large line and accessing pixel array crash happens. 因此,在读取第二条大行并访问像素阵列时会发生崩溃。

int i = 0, j = 0;
    char *token;

while(getline(&line, &len, file_stream) != EOF) {
    token = strtok(line, " \n\t");
    j = 0;                                          // <-- FIXED
    while (token != NULL) {
        //DEBUG("%s", token);
        img_struct->pixels[i][j].rgb[0] = strtol(token, NULL, 0);
        token = strtok(NULL, " \n\t");
        printf("%hu ", img_struct->pixels[i][j].rgb[0]);
        j++;
    }
    printf("\n");   
    i++;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM