Cannot convert char to const char error

The following code snippet (correctly) gives a warning in C and an error in C++ (using gcc & g++ respectively, tested with versions 3.4.5 and 4.2.1; MSVC does not seem to care): char **a; const...

However, in pure C, this still gives a warning, and I don’t understand why

You’ve already identified the problem — this code is not const-correct. «Const correct» means that, except for const_cast and C-style casts removing const, you can never modify a const object through those const pointers or references.

The value of const-correctness — const is there, in large part, to detect programmer errors. If you declare something as const, you’re stating that you don’t think it should be modified — or at least, those with access to the const version only should not be able to modifying it. Consider:

void foo(const int*);

As declared, foo doesn’t have permission to modify the integer pointed to by its argument.

If you’re not sure why the code you posted isn’t const-correct, consider the following code, only slightly different from HappyDude’s code:

char *y;

char **a = &y; // a points to y
const char **b = a; // now b also points to y

// const protection has been violated, because:

const char x = 42; // x must never be modified
*b = &x; // the type of *b is const char *, so set it 
         //     with &x which is const char* ..
         //     ..  so y is set to &x... oops;
*y = 43; // y == &x... so attempting to modify const 
         //     variable.  oops!  undefined behavior!
cout << x << endl;

Non-const types can only convert to const types in particular ways to prevent any circumvention of const on a data-type without an explicit cast.

Objects initially declared const are particularly special — the compiler can assume they never change. However, if b can be assigned the value of a without a cast, then you could inadvertently attempt to modify a const variable. This would not only break the check you asked the compiler to make, to disallow you from changing that variables value — it would also allow you break the compiler optimizations!

On some compilers, this will print 42, on some 43, and others, the program will crash.

Edit-add:

HappyDude: Your comment is spot on. Either the C langauge, or the C compiler you’re using, treats const char * const * fundamentally differently than the C++ language treats it. Perhaps consider silencing the compiler warning for this source line only.

I just want to initialize a const pointer with a non-const pointer. This should be work.

That’s not what you’re trying to do, no.

You’re trying to initialise a non-const pointer to pointer to const char, with a non-const pointer to pointer to char. That is never performed implicitly. Why? It’s well documented elsewhere because it’s not completely intuitive to all but, in short, if converting char** to const char** were allowed, then const-correctness would be violated.

It’s not the same as converting char** to char** const, which is what you think you’re trying to do.

It’s unfortunate that main‘s arguments do not already have const strewn about them. Sorry. Fortunately, you can work around it with a const_cast:

void foo(const char** argv) {}

int main(int argc, char** argv)
{
   foo(const_cast<const char**>(argv));
}

This is one of those situations in which using const_cast to hack around pre-existing silliness, contrary to the wishes of the type system, is actually okay.

  1. 12-06-2006


    #1

    ulillillia is offline


    Math wizard


    I use Visual C++ 2005 Express to make programs with, and I’m generally rather new to C programming although, from another tool, I’ve known the basic syntax style for a long time. I’m trying to learn how to read and write files to automate a process I do with a hex edittor that is rather boring, time consuming, and prone to mistakes. I have two major issues, the big one being the «cannot convert char to const char» error involving strcat. Because I don’t know how to convert an integer into a string without utilizing the number system, I figured I could just split the number into the digits 0 to 9 then add 48 to get the cooresponding digit character. I then thought of using strcat to stitch together these numbers to form the output, a file name (and path) in my case. This is where I’m stumped.

    Code:

    #include <stdio.h>
    #include <string.h>
    
    double sample_rate_base; // temporary for getting the fractional parts for rounding - 7 significant figures isn't quite enough given that sample rates go to 400,000
    unsigned int sample_rate; // integerical rounded value of the above variable
    signed short loop_position; // loop position for the creation of files
    signed short loop_start; // starting point of the loop
    signed short loop_end; // the point where the loop will end
    unsigned int bytes_per_second; // equal to sample_rate*multiplier
    char multiplier; // the multiplier used for the bytes_per_second variable
    char file_head_start[24]; // for copying identical file header data
    char file_head_end[7]; // for copying the last parts of the file header data
    unsigned int file_length; // the length of the file after the header data in bytes
    char file_contents[]; // the contents of the file for copying, since the samples themselves don't change at all
    char file_name[]; // the file name for the output file
    
    FILE *file_pointer;
    
    void find_next_sample_rate()
    {
    	// Based on the new 48-step speed system
    	if (loop_position < -72)
    	{
    		sample_rate_base += (208.0+(1.0/3.0)); // 208 1/3
    	}
    
    	if (loop_position == -72)
    	{
    		sample_rate_base = 17500.0; // a special case to prevent rounding flaws from the float - I may need the double
    	}
    	
    	if ((loop_position > -72) && (loop_position <= -48))
    	{
    		sample_rate_base += 312.5;
    	}
    	
    	if ((loop_position > -48) && (loop_position <= -24))
    	{
    		sample_rate_base += (416.0+(2.0/3.0)); // 416 2/3
    	}
    	
    	if ((loop_position > -24) && (loop_position <= 0))
    	{
    		sample_rate_base += 625.0;
    	}
    	
    	if ((loop_position > 0) && (loop_position <= 24))
    	{
    		sample_rate_base += (833.0+(1.0/3.0)); // 833 1/3
    	}
    	
    	if ((loop_position > 24) && (loop_position <= 48))
    	{
    		sample_rate_base += 1250.0;
    	}
    	
    	if ((loop_position > 48) && (loop_position <= 72))
    	{
    		sample_rate_base += (1666.0+(2.0/3.0)); // 1666 2/3
    	}
    	
    	if ((loop_position > 72) && (loop_position <= 96))
    	{
    		sample_rate_base += 2500.0;
    	}
    	
    	if ((loop_position > 96) && (loop_position <= 120))
    	{
    		sample_rate_base += (3333.0+(1.0/3.0)); // 3333 1/3
    	}
    	
    	if (loop_position > 120)
    	{
    		sample_rate_base += 5000.0;
    	}
    	
    	loop_position += 1; // advance the loop position
    	sample_rate = (int)(sample_rate_base+0.5); // use starting value first and round it off
    	bytes_per_second = sample_rate*multiplier;
    }
    
    void get_new_file_name()
    {
    	// chars 48 through 57 are the numbers
    	char digit_1;
    	char digit_10;
    	char digit_100;
    	char digit_1000;
    	char digit_10000;
    	char digit_100000;
    	int remaining_part;
    	
    	digit_100000 = sample_rate/100000; // since integers are used, and junk after the decimal is ignored, only a single digit is present - breaks up numbers from 12500 to 400000 into digits
    	remaining_part = sample_rate-(100000*digit_100000); // gets rid of the 100,000's digit leaving 5 digits left
    	digit_100000 += 48; // shifts the digit value into the cooresponding character on the character map since 48 through 57 (decimal) are the digits
    	digit_10000 = remaining_part/10000; // continue splitting the number into the separate digits
    	remaining_part -= (10000*digit_10000);
    	digit_10000 += 48;
    	digit_1000 = remaining_part/1000;
    	remaining_part -= (1000*digit_1000);
    	digit_1000 += 48;
    	digit_100 = remaining_part/100;
    	remaining_part -= (100*digit_100);
    	digit_100 += 48;
    	digit_10 = remaining_part/10;
    	remaining_part -= (10*digit_10);
    	digit_10 += 48;
    	digit_1 = remaining_part;
    	digit_1 += 48;
    	
    	digit_100000 = (const char)digit_100000; // random test
    	strcpy(file_name, "C:\My Documents\Songs for MP3\Desert Zone\");
    	
    	if (loop_end >= 48) // if the highest possible is 100,000 or greater, add a sixth digit
    	{
    		strcat(file_name, digit_100000); // a special case - write only if base sample rate is 6 or more digits but write the leading 0
    	}
    	
    	strcat(file_name, digit_10000); // add the main common digits to the file name that are always present
    	strcat(file_name, digit_1000);
    	strcat(file_name, digit_100);
    	strcat(file_name, digit_10);
    	strcat(file_name, digit_1);
    	strcat(file_name, " Desert Zone.wav"); // add the space at the end with the null character terminating the string
    }
    
    void create_output_files()
    {
    	/*
    	notes about loop ranges (based of of the spreadsheet document):
    	-96, 12500 Hz
    	-84, 15000 Hz
    	-72, 17500 Hz
    	-64, 20000 Hz (extended minimum 50K)
    	-56, 22500 Hz (rarely used)
    	-48, 25000 Hz (standard minimum 50K)
    	-36, 30000 Hz (100K)
    	-24, 35000 Hz (100K)
    	-16, 40000 Hz (extended minimum 100K)
    	 -8, 45000 Hz (100K)
    	  0, 50000 Hz (standard minimum 100K)
    	 15, 62500 Hz (standard maximum 50K)
    	 24, 70000 Hz (extended maximum 50K)
    	 32, 80000 Hz (50K)
    	 40, 90000 Hz (50K)
    	 48, 100000 Hz (50K)
    	 63, 125000 Hz (standard maximum 100K)
    	 72, 140000 Hz (extended maximum 100K)
    	 80, 160000 Hz
    	 88, 180000 Hz
    	 96, 200000 Hz
    	108, 240000 Hz
    	120, 280000 Hz
    	128, 320000 Hz
    	136, 360000 Hz
    	144, 400000 Hz
    	*/
    
    	// first, set the range using the chart commented out above
    	
    	char temp_var;
    	
    	loop_start = -48; // starting point
    	loop_end = 15; // ending point
    	loop_position = loop_start; // start at the loop starting point
    	sample_rate = 25000; // copy sample rate from chart above with loop_position as the value to take from
    	bytes_per_second = sample_rate*multiplier;
    	
    	while(loop_position <= loop_end) // should create 64 files
    	{
    		printf("Current progress:  %d Hz, %d of %d processedn", sample_rate, loop_position-loop_start, loop_end-loop_start);
    		scanf("%d", &temp_var); // to stop input to see results for testing
    		get_new_file_name(); // get the strings stitched together for the output file name
    		/*
    		file_pointer = fopen(file_name, "wb"); // open the file for writing in binary mode (WAV files are binary)
    		fwrite(file_head_start, 1, 24, file_pointer); // write the details in the same order as it was read in
    		fwrite(sample_rate, 4, 1, file_pointer);
    		fwrite(bytes_per_second, 4, 1, file_pointer);
    		fwrite(multiplier, 1, 1, file_pointer);
    		fwrite(file_head_end, 1, 7, file_pointer);
    		fwrite(file_length, 4, 1, file_pointer);
    		fwrite(file_contents, 1, file_length, file_pointer); // copies all the rest of the data, the samples themselves
    		fclose(file_pointer); // close the file to reuse the pointer (or is it handle as with Gamestudio?)
    		*/
    		
    		loop_position += 1; // increment the loop for another round
    		find_next_sample_rate();
    	}
    }
    
    void read_base_file()
    {
    	// this copies the full structure of the WAV file, since only 8 bytes are changed out of several million
    	/*
    	file_pointer = fopen("C:\My Documents\Songs for MP3\Desert Zone\Desert Zone base.wav", "rb"); // assign a pointer (or handle?) for handling the file
    	fread(file_head_start, 1, 24, file_pointer); // read into file_head_start in one-byte chunks and fill the array of 24 elements with the given file pointer
    	fread(sample_rate, 4, 1, file_pointer); // same as above but read a 4-byte chunk once instead
    	fread(bytes_per_second, 4, 1, file_pointer); // same as above
    	fread(multiplier, 1, 1, file_pointer); // read a one-byte chunk once instead of the above
    	fread(file_head_end, 1, 7, file_pointer); // read a one-byte chunk 7 times to fill the file header data's end
    	fread(file_length, 4, 1, file_pointer); // read the file length data value, the number of bytes after the head
    	fread(file_contents, 1, file_length, file_pointer); // read one-byte chunks for the entire file's length, which is the end of the file
    	fclose(file_pointer); // close the file
    	*/
    	
    	create_output_files(); // initiate the loop for creating the output files copying the data above changing the 8 bytes as needed
    }
    
    int main()
    {
    	read_base_file();
    }

    The get_new_file_name() function is where the errors are occurring due to strcat. strcpy works just fine (no errors nor warnings), but it’s the part of stitching the numbers from the process above it together to form the end result.

    The file-related instructions are commented out as I first want to test to see if the other parts work as they should. Once I finish that, fixing any bugs, I’d then test the file inputs.

    What I’m trying to do is generate several WAV files with only the «sample rate» and «bytes per second» values changed (as to change the speed without any degradation; a mere 8 bytes). I currently do this using a hex edittor and I don’t have any problems with that (as the results play back without any trouble). Only 8 bytes in the entire file get changed. The sample rate varies from 12500 Hz to as high as 400,000 Hz at the extreme ends, both of which play back just fine. Since only 8 bytes change, I figure it’d be better to just load the contents of the base file into memory (the source) then write the outputs with only the 8 bytes changed accordingly. The second thing I’m concerned about is whether or not I used the file instructions properly. That is, when a file is opened, it starts at the first byte of the file and after each read or write instruction, it advances accordingly. That is, if 24 bytes were read followed by an instruction to read a group of 4 bytes, it would read at the 25th byte rather than go back to the first byte. The file is closed to allow for reusing the handle or pointer (not sure which it is — it’s a handle in my other tool I used which is very limited) for another file. The code should generate 64 WAV files of the same file size as the source, a bit over 46 MB.


  2. 12-06-2006


    #2

    Salem is offline


    and the hat of int overfl

    Salem's Avatar


    > get_new_file_name
    Seems an awfully long winded way of doing

    Code:

    sprintf( file_name,
             "C:\My Documents\Songs for MP3\Desert Zone\%06d\Desert Zone.wav"
             sample_rate );

    > // add the space at the end with the null character terminating the string
    String constants always have a at the end, you’re just wasting effort adding another one.

    > char file_contents[]; // the contents of the file for copying, since the samples themselves don’t change at all
    > char file_name[]; // the file name for the output file
    You need to allocate space yourself.
    The compiler won’t magically work out how much space you need.

    Also, why are there so many global variables and so few parameters?


  3. 12-06-2006


    #3

    dwks is offline


    Frequently Quite Prolix

    dwks's Avatar


    strcat expects a string (char*) and you’re passing it a single character (char).

    You can use sprintf(), or manipulate the string directly, setting the NULL to the new character and shifting the NULL the the next character.

    Code:

    	if ((loop_position > -72) && (loop_position <= -48))
    	{
    		sample_rate_base += 312.5;
    	}
    	
    	if ((loop_position > -48) && (loop_position <= -24))
    	{
    		sample_rate_base += (416.0+(2.0/3.0)); // 416 2/3
    	}
    	
    	if ((loop_position > -24) && (loop_position <= 0))
    	{
    		sample_rate_base += 625.0;
    	}

    You could write that much more concisely with else if statements.

    Code:

    char file_name[]; // the file name for the output file

    You probably want a size in there.

    dwk

    Seek and ye shall find. quaere et invenies.

    «Simplicity does not precede complexity, but follows it.» — Alan Perlis
    «Testing can only prove the presence of bugs, not their absence.» — Edsger Dijkstra
    «The only real mistake is the one from which we learn nothing.» — John Powell

    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.


  4. 12-06-2006


    #4

    ulillillia is offline


    Math wizard


    Quote Originally Posted by Salem

    > get_new_file_name
    Seems an awfully long winded way of doing

    Code:

    sprintf( file_name,
             "C:\My Documents\Songs for MP3\Desert Zone\%06d\Desert Zone.wav"
             sample_rate );

    The only reason I did all that was because I didn’t know of any other method (I didn’t know of the sprintf function).

    > // add the space at the end with the null character terminating the string
    String constants always have a at the end, you’re just wasting effort adding another one.

    I wasn’t too sure on this so I added it just to be safe (since the null terminating character is extremely important).

    > char file_contents[]; // the contents of the file for copying, since the samples themselves don’t change at all
    > char file_name[]; // the file name for the output file
    You need to allocate space yourself.
    The compiler won’t magically work out how much space you need.

    Also, why are there so many global variables and so few parameters?

    Because the file sizes vary a lot (from barely 1 MB to nearly 700 MB at the extreme high end), having to right-click on every base WAV file in Windows Explorer to view the file size and copy it is a bit ridiculous. With the 94,172,862-byte base file, about in my typical size range, an array with 100,000,000 items just wastes a lot of space, even if I went with 95 MB.

    The reason for all the global variables is that I know they are faster to use and there are many of them that get changed in the functions that others use. The whole thing is otherwise an entire loop. The «get_new_file_name» function is used with the «create_output_files» function. The «find_next_sample_rate» function is also used within the «create_output_files» function. By separating these separate tasks, it helps organize things better. This is only for my home use to help automate a rather boring task and thus optimization and speed really aren’t all that important. Thanks though for the assistance. I’m still used of the numerous limitations of my old tool, the reason for going with C. Using else if is one of those limitations I’m used to so I’m used of just using a long series of if statements without any else used. There’s so much new stuff with C that I’m not used to and it would take a while to break away from the habits I’ve developed with the old tool I’ve used for about a year.


  5. 12-06-2006


    #5

    Salem is offline


    and the hat of int overfl

    Salem's Avatar


    And saying char array[ ]; is typically 0 bytes — not so good is it?

    Anyway, even with very large files, there is seldom any need to store the WHOLE thing in memory at one go.

    Even if you do, there is such a thing as finding out the size of the file, then allocating memory to match the file size.


  6. 12-06-2006


    #6

    ulillillia is offline


    Math wizard


    Well, I fixed a few of the bugs I had without the file stuff, but now I’ve got another problem very related to the original. In the «read_base_file» function at the bottom, I uncommented the file-related instructions to check to see if they work. The build log gives a rather bizarre set of errors, almost randomly chosen. I get this:

    —— Build started: Project: WAV file sample rate generator, Configuration: Debug Win32 ——
    Compiling…
    WAV file sample rate generator.cpp
    .WAV file sample rate generator.cpp(131) : warning C4996: ‘sprintf’ was declared deprecated
    C:Program FilesMicrosoft Visual Studio 8VCincludestdio.h(345) : see declaration of ‘sprintf’
    Message: ‘This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.’
    .WAV file sample rate generator.cpp(136) : warning C4996: ‘sprintf’ was declared deprecated
    C:Program FilesMicrosoft Visual Studio 8VCincludestdio.h(345) : see declaration of ‘sprintf’
    Message: ‘This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.’
    .WAV file sample rate generator.cpp(140) : warning C4996: ‘scanf’ was declared deprecated
    C:Program FilesMicrosoft Visual Studio 8VCincludestdio.h(295) : see declaration of ‘scanf’
    Message: ‘This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.’
    .WAV file sample rate generator.cpp(161) : warning C4996: ‘fopen’ was declared deprecated
    C:Program FilesMicrosoft Visual Studio 8VCincludestdio.h(234) : see declaration of ‘fopen’
    Message: ‘This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.’
    .WAV file sample rate generator.cpp(163) : error C2664: ‘fread’ : cannot convert parameter 1 from ‘unsigned int’ to ‘void *’
    Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
    .WAV file sample rate generator.cpp(164) : error C2664: ‘fread’ : cannot convert parameter 1 from ‘unsigned int’ to ‘void *’
    Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
    .WAV file sample rate generator.cpp(165) : error C2664: ‘fread’ : cannot convert parameter 1 from ‘char’ to ‘void *’
    Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
    .WAV file sample rate generator.cpp(167) : error C2664: ‘fread’ : cannot convert parameter 1 from ‘unsigned int’ to ‘void *’
    Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
    Build log was saved at «file://c:My DocumentsMy programsWAV file sample rate generatorWAV file sample rate generatorDebugBuildLog.htm»
    WAV file sample rate generator — 4 error(s), 4 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

    Line 161 is where the fopen instruction is. The line below it (162), strangely enough, does not have any problems. Lines 163 through 165 produce errors. Line 166 is just fine (no errors) 167 is errored and 168 is also just fine. The fclose instruction works just fine. Why the randomness and the errors? The variables sample_rate and bytes_per_second are both 32-bit integers. I’m confused about this.


  7. 12-06-2006


    #7

    Salem is offline


    and the hat of int overfl

    Salem's Avatar


    > WAV file sample rate generator.cpp
    You’re compiling your C program with a C++ compiler.

    Rename it to be a .c file.

    > _CRT_SECURE_NO_DEPRECATE
    In the project settings for the compiler, under the preprocessor section, you should be able to define your own conditional compilation flags. Add this flag to that list

    Alternatively, this on the very first line, before any includes should also work

    Code:

    #define _CRT_SECURE_NO_DEPRECATE

    > .WAV file sample rate generator.cpp(163) : error C2664: ‘fread’ : cannot convert parameter 1 from ‘unsigned int’ to ‘void *’
    Things like this
    fread(sample_rate, 4, 1, file_pointer);
    Need to be like this
    fread( &sample_rate, 4, 1, file_pointer);


  8. 12-06-2006


    #8

    vart is offline


    Hurry Slowly

    vart's Avatar


    Note also that your read procedure is not compatible with the wave file format

    There are no restrictions upon the order of the chunks within a WAVE file, with the exception that the Format chunk must precede the Data chunk. Some inflexibly written programs expect the Format chunk as the first chunk (after the RIFF header) although they shouldn’t because the specification doesn’t require this.

    Read this http://www.borg.com/~jglatt/tech/wave.htm
    You should always start with reading the chunk format and size
    when analyze format tag and deceide if you want to skip size bytes or parse them
    header size can be different depending on the compression used — so you should avoid code like

    Code:

    fread(file_head_end, 1, 7, file_pointer); // read a one-byte chunk 7 times to fill the file header data's end

    that uses magical numbers… they will be correct with only several files, with others your code will fail

    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    � David J. Wheeler


  9. 12-07-2006


    #9

    ulillillia is offline


    Math wizard


    Quote Originally Posted by vart

    Note also that your read procedure is not compatible with the wave file format

    Read this http://www.borg.com/~jglatt/tech/wave.htm
    You should always start with reading the chunk format and size
    when analyze format tag and deceide if you want to skip size bytes or parse them
    header size can be different depending on the compression used — so you should avoid code like

    Code:

    fread(file_head_end, 1, 7, file_pointer); // read a one-byte chunk 7 times to fill the file header data's end

    that uses magical numbers… they will be correct with only several files, with others your code will fail

    The reason why I did it that way was because I’m merely copying files with only 8 bytes changed. To help understand:

    The first 24 bytes are the same in every file within the group. The next 4 bytes, the sample rate, is different for each file. With the sample rate changing, the «bytes per second» value, the next 4 bytes after it, also change, of which is multiplied by the value in the next byte after this, the reason for reading that separate, since it doesn’t change. The next 7 bytes after this are merely copied with the next 4 being the length of the data part of the file, of which is the file size minus 44 (44 bytes is how big the header data is). For file to be copied properly, I need this value and thus it is read separately. The last of the data, the samples, are merely just copied as is.

    When the output files are written, the first 24 bytes are written since they never change. The sample rate is then changed according to the little piece of code to find the resulting value (which then converts it to an integer and rounds it to the nearest whole number to provide maximum possible precision). Since the bytes per second value is the result of sample_rate*multiplier, this value is set based on that. The multiplier is usually 2 since I work with 16-bit mono files, but sometimes 24-bit mono giving a multiplier of 3. The multiplier value is copied from what was read in the source file since it never changes and the 7 bytes after that are also copied since they don’t change. The file length never changes either and thus is copied as well as all the file data after it. The loop starts again with the same thing happening only a different sample rate and «bytes per second» value are used.

    Just to give you an idea, here’s a screenshot I took quite a while ago that shows you what data I use. Unlike the third highlighted value, the «bit depth» as shown in the screenshot, I use the multiplier value read directly after the «bytes per second» value, highlighted in red. The sample rate is highlighted in blue. The 24 bytes to the left are not changed in each file and are merely copied. Everything else after the «bytes per second» value is also copied without modification. Just the blue and red highlighted areas are changed in each file, a mere 8 bytes. By changing these 8 bytes in the hex edittor and playing the change in any audio player (Winamp in my case), it plays back just as I expected. If I change the sample rate from 48,000 Hz to 40,000 Hz, the file would be 20% longer with the pitch 5/6 that of what it was (instead of 1200 Hz, it plays as 1000 Hz). If I later change it again to 32,000 Hz, it would play back even slower with an even lower pitch (1200 Hz would be 800 Hz and would play 50% longer than the original 48,000 Hz).

    Edit: making the change to a .c file instead of .cpp, it now compiles without any errors, but the program doesn’t run at all like it was and the warnings show something weird with lines 163, 164, 165, and 167, those same ones giving the errors in my previous case. The build log shows this for the relavent area.

    .WAV file sample rate generator.c(163) : warning C4022: ‘fread’ : pointer mismatch for actual parameter 1
    .WAV file sample rate generator.c(164) : warning C4022: ‘fread’ : pointer mismatch for actual parameter 1
    .WAV file sample rate generator.c(165) : warning C4022: ‘fread’ : pointer mismatch for actual parameter 1
    .WAV file sample rate generator.c(167) : warning C4022: ‘fread’ : pointer mismatch for actual parameter 1

    Pointer mismatch? This doesn’t make sense as it works just fine with other fread instructions in the same group. What’s so special about lines 162, 166, and 168 that don’t cause problems whereas the other lines in the same group with the same instructions used do? That’s probably why it couldn’t compile it as a C++ file.

    In the debug dialog, I get this at the end:

    The program ‘[3956] WAV file sample rate generator.exe: Native’ has exited with code -1073741811 (0xc000000d).

    What does this mean?

    Last edited by ulillillia; 12-07-2006 at 03:01 AM.


  10. 12-07-2006


    #10

    Salem is offline


    and the hat of int overfl

    Salem's Avatar


    > The program ‘[3956] WAV file sample rate generator.exe: Native’ has exited with code -1073741811 (0xc000000d).
    It means your int main doesn’t have a return 0; at the end. So the actual return value just happens to be whatever happened to be lying around in some register or other.
    C++ will assume this is what you meant, C does not.

    > .WAV file sample rate generator.c(163) : warning C4022: ‘fread’ : pointer mismatch for actual parameter 1
    Seems odd — can you post your latest code please.

    Some older compilers assume fread() takes a char* as the first parameter rather than a void* (as required by ANSI-C).
    This obviously works fine if what you’re reading into is in fact a char array.


  11. 12-07-2006


    #11

    ulillillia is offline


    Math wizard


    Okay, so I added the «return(0);» at the end of the main function. Oddly enough, I didn’t get any errors as it does with any other function.

    I don’t think «Visual C++ 2005 Express», the program I use to write and compile programs with, is an old compiler. Afterall, I downloaded it from Microsoft’s website about 2 or 3 weeks ago.

    You wanted the updated code so here it is:

    Code:

    #include <stdio.h>
    #include <string.h>
    
    double sample_rate_base; // temporary for getting the fractional parts for rounding - 7 significant figures isn't quite enough given that sample rates go to 400,000
    unsigned int sample_rate; // integerical rounded value of the above variable
    signed short loop_position; // loop position for the creation of files
    signed short loop_start; // starting point of the loop
    signed short loop_end; // the point where the loop will end
    unsigned int bytes_per_second; // equal to sample_rate*multiplier
    char multiplier; // the multiplier used for the bytes_per_second variable
    char file_head_start[24]; // for copying identical file header data
    char file_head_end[7]; // for copying the last parts of the file header data
    unsigned int file_length; // the length of the file after the header data in bytes
    char file_contents[95000000]; // the contents of the file for copying, since the samples themselves don't change at all // use array with size bigger than file size
    char file_name[128]; // the file name for the output file
    
    FILE *file_pointer;
    
    void find_next_sample_rate()
    {
    	// Based on the new 48-step speed system
    	if (loop_position < -72)
    	{
    		sample_rate_base += (208.0+(1.0/3.0)); // 208 1/3
    	}
    	
    	else if (loop_position == -72)
    	{
    		sample_rate_base = 17500.0; // a special case to prevent rounding flaws from the double
    	}
    	
    	else if ((loop_position > -72) && (loop_position <= -48))
    	{
    		sample_rate_base += 312.5;
    	}
    	
    	else if ((loop_position > -48) && (loop_position <= -24))
    	{
    		sample_rate_base += (416.0+(2.0/3.0)); // 416 2/3
    	}
    	
    	else if ((loop_position > -24) && (loop_position <= 0))
    	{
    		sample_rate_base += 625.0;
    	}
    	
    	else if ((loop_position > 0) && (loop_position <= 24))
    	{
    		sample_rate_base += (833.0+(1.0/3.0)); // 833 1/3
    	}
    	
    	else if ((loop_position > 24) && (loop_position <= 48))
    	{
    		sample_rate_base += 1250.0;
    	}
    	
    	else if ((loop_position > 48) && (loop_position <= 72))
    	{
    		sample_rate_base += (1666.0+(2.0/3.0)); // 1666 2/3
    	}
    	
    	else if ((loop_position > 72) && (loop_position <= 96))
    	{
    		sample_rate_base += 2500.0;
    	}
    	
    	else if ((loop_position > 96) && (loop_position <= 120))
    	{
    		sample_rate_base += (3333.0+(1.0/3.0)); // 3333 1/3
    	}
    	
    	else // for beyond 120
    	{
    		sample_rate_base += 5000.0;
    	}
    	
    	sample_rate = (int)(sample_rate_base+0.5); // use starting value first and round it off
    	bytes_per_second = sample_rate*multiplier;
    }
    
    void create_output_files()
    {
    	/*
    	notes about loop ranges (based of of the spreadsheet document):
    	-96, 12500 Hz
    	-84, 15000 Hz
    	-72, 17500 Hz
    	-64, 20000 Hz (extended minimum 50K)
    	-56, 22500 Hz (rarely used)
    	-48, 25000 Hz (standard minimum 50K)
    	-36, 30000 Hz (100K)
    	-24, 35000 Hz (100K)
    	-16, 40000 Hz (extended minimum 100K)
    	 -8, 45000 Hz (100K)
    	  0, 50000 Hz (standard minimum 100K)
    	 15, 62500 Hz (standard maximum 50K)
    	 24, 70000 Hz (extended maximum 50K)
    	 32, 80000 Hz (50K)
    	 40, 90000 Hz (50K)
    	 48, 100000 Hz (50K)
    	 63, 125000 Hz (standard maximum 100K)
    	 72, 140000 Hz (extended maximum 100K)
    	 80, 160000 Hz
    	 88, 180000 Hz
    	 96, 200000 Hz
    	108, 240000 Hz
    	120, 280000 Hz
    	128, 320000 Hz
    	136, 360000 Hz
    	144, 400000 Hz
    	*/
    
    	// first, set the range using the chart commented out above
    	
    	char temp_var;
    	
    	loop_start = -48; // starting point
    	loop_end = 15; // ending point
    	loop_position = loop_start; // start at the loop starting point
    	sample_rate = 25000; // copy sample rate from chart above with loop_position as the value to take from
    	sample_rate_base = sample_rate;
    	bytes_per_second = sample_rate*multiplier;
    	
    	while(loop_position <= loop_end) // should create 64 files
    	{
    		printf("Current progress:  %d Hz, %d of %d processedn", sample_rate, loop_position-loop_start, loop_end-loop_start+1); // temporary items for debugging purposes
    		printf("loop_position:  %d, multiplier:  %d, sr base:  %6.3fn", loop_position, multiplier, sample_rate_base);
    		
    		if (loop_end >= 48) // if 6 figure sample rates are expected, a leading zero is needed to allow for the speeds to be sorted properly from slowest to fastest
    		{
    			sprintf(file_name, "C:\My Documents\Songs for MP3\Desert Zone\%06d Desert Zone.wav", sample_rate);
    		}
    		
    		else // if only 5-figure sample rates are expected, the value can be left as is
    		{
    			sprintf(file_name, "C:\My Documents\Songs for MP3\Desert Zone\%05d Desert Zone.wav", sample_rate);
    		}
    		
    		printf(file_name); // to make sure the file name is set properly, again for debugging reasons
    		scanf("%d", &temp_var); // to stop input to see results for testing
    		/*
    		file_pointer = fopen(file_name, "wb"); // open the file for writing in binary mode (WAV files are binary)
    		fwrite(file_head_start, 1, 24, file_pointer); // write the details in the same order as it was read in
    		fwrite(sample_rate, 4, 1, file_pointer);
    		fwrite(bytes_per_second, 4, 1, file_pointer);
    		fwrite(multiplier, 1, 1, file_pointer);
    		fwrite(file_head_end, 1, 7, file_pointer);
    		fwrite(file_length, 4, 1, file_pointer);
    		fwrite(file_contents, 1, file_length, file_pointer); // copies all the rest of the data, the samples themselves
    		fclose(file_pointer); // close the file to reuse the pointer (or is it handle as with Gamestudio?)
    		*/
    		
    		loop_position += 1; // increment the loop for another round
    		find_next_sample_rate();
    	}
    }
    
    int main()
    {
    	// this copies the full structure of the WAV file into memory for the output files later, since only 8 bytes are changed out of several million
    	file_pointer = fopen("C:\My Documents\Songs for MP3\Desert Zone\Desert Zone base.wav", "rb"); // assign a pointer (or handle?) for handling the file and read in binary mode
    	fread(file_head_start, 1, 24, file_pointer); // read into file_head_start in one-byte chunks and fill the array of 24 elements with the given file pointer
    	fread(sample_rate, 4, 1, file_pointer); // same as above but read a 4-byte chunk once instead
    	fread(bytes_per_second, 4, 1, file_pointer); // same as above
    	fread(multiplier, 1, 1, file_pointer); // read a one-byte chunk once instead of the above
    	fread(file_head_end, 1, 7, file_pointer); // read a one-byte chunk 7 times to fill the file header data's end
    	fread(file_length, 4, 1, file_pointer); // read the file length data value, the number of bytes after the head
    	fread(file_contents, 1, file_length, file_pointer); // read one-byte chunks for the entire file's length, which is the end of the file
    	fclose(file_pointer); // close the file
    	
    	create_output_files(); // initiate the loop for creating the output files copying the data above changing the 8 bytes as needed
    	return(0);
    }

    You may note a few changes, some of those mentioned in this thread being some. Before I uncommented the file reading lines, I tested things and fixed a few bugs I encountered.

    I also recompiled the program after the return(0); was added and I still get the same exit code value. By commenting out the file read instructions at the end, I get the message in the debug dialog saying:

    The program ‘[2392] WAV file sample rate generator.exe: Native’ has exited with code -1073741510 (0xc000013a).

    The program ran successfully though and didn’t abruptly close. There’s something seriously wrong with the file instructions.


  12. 12-07-2006


    #12

    vart is offline


    Hurry Slowly

    vart's Avatar


    fread(sample_rate, 4, 1, file_pointer);

    should be
    fread(&sample_rate, 4, 1, file_pointer);

    the same for other non-array variables
    and check the file_length before reading into file_contents array

    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    � David J. Wheeler


  13. 12-07-2006


    #13

    ulillillia is offline


    Math wizard


    I was using the example here at the bottom to do that but the ampersand was not there at the beginning which is why it didn’t work like that. I made this fix and, although there was a two-second delay before I saw the printed details come up, I checked Windows Task Manager and saw that it read the 94-million some bytes I was expecting to see and thus I can tell it’s working. I expected a delay of about that time span since that’s about the typical maximum my hard drive can read and write at a sustained speed. It was just over 50,000 before this. I take it the write instructions also need this. Oh well, more testing. Thanks for the help .


  14. 12-07-2006


    #14

    vart is offline


    Hurry Slowly

    vart's Avatar


    Quote Originally Posted by ulillillia

    In this example x is an array, and it means it is an address of the first element.

    In your code there is no problem with arrays… But non arrays variable should be passed by pointer…

    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    � David J. Wheeler


  15. 12-07-2006


    #15

    ulillillia is offline


    Math wizard


    Oh, I see now. Perhaps this detail could be added to that tutorial.

    Anyway, I’ve fixed the bugs and had it write the output files. The WAV files it wrote played back just fine and in the way I expected. With this program, I can process what I was doing with the hex edittor nearly ten times faster. Thank you for the assistance. I appreciate it. Now to bulk-convert all the resulting WAV files into MP3 — time for Audacity.


INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Thanks. We have received your request and will respond promptly.

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!

  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It’s Free!

*Tek-Tips’s functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

cannot convert parameter 1 from ‘char’ to ‘const char *’

cannot convert parameter 1 from ‘char’ to ‘const char *’

(OP)

11 Oct 07 11:57

Dear Experts,

I am stuck up with a piece of code, which I am not able to break. Could you kindly help me out.

Situation:
I am trying to perform a string comparison between 2 variables, one defined as const TCHAR * and other defined as CS_CHAR, inside an Embedded SQL program in C++. My relevant code snippet is as below:

=====
short CSQLBox::fnTest(const TCHAR *varInput)
{
  CS_CHAR szExtract;

    //szExtract variable is populated by Embedded SQL query
  ….

  //Do string comparison
  if(strcmp(szExtract, varInput)==0)
  {
    …
  }
}
=====

When I try to compile this code, the strcmp step is throwing an error «cannot convert parameter 1 from ‘char’ to ‘const char *'».

I have tried typecasting parameter 1 as:
if(strcmp((const char*)szExtract, varInput)==0)

This way, the code compiles, but fails in runtime with unhandled exception error. I am unable to understand how to solve this issue.

Could anyone kindly offer me some suggestions.

cheers,
sanK

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Join Tek-Tips® Today!

Join your peers on the Internet’s largest technical computer professional community.
It’s easy to join and it’s free.

Here’s Why Members Love Tek-Tips Forums:

  • Tek-Tips ForumsTalk To Other Members
  • Notification Of Responses To Questions
  • Favorite Forums One Click Access
  • Keyword Search Of All Posts, And More…

Register now while it’s still free!

Already a member? Close this window and log in.

Join Us             Close

> однако, в чистом C, это все еще дает предупреждение, и я не понимаю, почему

вы уже определили проблему — этот код не является const-правильный. «Const correct» означает, что за исключением приведений const_cast и C-style, удаляющих const, вы никогда не сможете изменить объект const с помощью этих указателей или ссылок const.

значение const-correctness — const существует, в значительной степени, для обнаружения ошибок программиста. Если вы объявляете что-то как const, вы заявив, что вы не думаете, что он должен быть изменен-или, по крайней мере, те, у кого есть доступ только к версии const, не должны быть в состоянии изменить его. Рассмотрим:

void foo(const int*);

Как объявлено, foo не имеет разрешение чтобы изменить целое число, на которое указывает его аргумент.

Если вы не уверены, почему код, который вы опубликовали, не является const-правильным, рассмотрите следующий код, только немного отличающийся от кода HappyDude:

char *y;

char **a = &y; // a points to y
const char **b = a; // now b also points to y

// const protection has been violated, because:

const char x = 42; // x must never be modified
*b = &x; // the type of *b is const char *, so set it 
         //     with &x which is const char* ..
         //     ..  so y is set to &x... oops;
*y = 43; // y == &x... so attempting to modify const 
         //     variable.  oops!  undefined behavior!
cout << x << endl;

типы Non-const могут только преобразование в типы const в частности способы предотвращения любого обхода «const» на типе данных без явного приведения.

объекты, первоначально объявленные const, являются особенно особенными-компилятор может предположить, что они никогда не изменяются. Однако, если ‘b’ может быть присвоено значение ‘a’ без приведения, то вы можете непреднамеренно попытаться изменить переменную const. Это не только нарушит проверку, которую вы попросили компилятор сделать, чтобы запретить вам изменять эти переменные значение — это также позволит вам сломать оптимизацию компилятора!

На некоторых компиляторах это будет печатать ’42’, на некоторых’ 43 ‘ и других, программа выйдет из строя.

Edit-add:

HappyDude:ваш комментарий находится на месте. Либо язык C, либо компилятор C, который вы используете, трактует const char * const * принципиально иначе, чем язык C++. Возможно, следует отключить предупреждение компилятора для этой исходной строки только.

Edit-delete: удалены опечатка

Regardless of the findings below, you don’t really want to compare a string object with a null-character this way (more on that below). Really something like: if (someArduinoStringObj.isEmpty()) { is a better idea, no matter what core you’re on.

So for anyone that has landed here with this problem with code that had worked and no longer works, the answer is basically don’t do that; probably shouldn’t have been doing that in the first place.

If you’re curious on what I found, there’s material on that below.


So, I don’t have a complete handle on this, but I do have something to report. When we started going through this I didn’t think there would be anything going on in the Arduino board support packages that would have any effect on this, but it turns out that’s not the case.

We worked out that under ESP8266 Arduino core 3.0.0 the lines of the following form fail to compile and under version 2.7.4 the compile without error. Here under 3.0.0 it was not picky about specifically loginPassword.

if (someArduinoStringObj == '') someArduinoStringObj = "some literal";

This can be abstracted to the somewhat nonsensical:

someArduinoStringObj == '';

Since that’s the part makes the difference. I really thought there was something more clever going on in the WString.h/WString.cpp code, an extra constructor or implicit conversion operator call prior to the code for the == operator. There is an explicit constructor for String that takes a single char, but it’s just that, it’s explicit; it doesn’t take part in evaluating the == expression above. And there’s no automatic conversion from String to const char *. It turns out that isn’t anything clever going on in String class when it comes to this problem. In fact you can boil this down to something similar so that the String class itself isn’t actually involved at all, into:

void func(const char *) {}

void setup() {
  func('');
}

// ...

This will likewise pass compilation under 2.7.4 and fail with a similar error message under 3.0.0. So, with String it is just trying to call the operator==(const char *), even though it’s being given a char type. Before getting into that, I tested a theory, which was to find out what happens if given == '1'; or == 'X') etc, any non-zero value, because 0 has had an interesting relationship with pointers in C++ and C. It makes more sense once you realize there’s special going on in String.h. We’re basically talking about func('') vs func('1') or func('X') Well, under 2.7.4 these values fail where » does not, but under 3.0.0 both fail. So I got looking into the platform.txt file on both core versions, thinking maybe I’ll spot a difference in compiler options. E.g. it would make «sense» if 2.7.4 had -fpermissive where 3.0.0. didn’t, but that’s not the case. The major difference is that 3.0.0 has -std=g++17 and 2.7.4 has -std=g++11. Just for the hell of it I stole the command-line out of the verbose output compiling for the .ino.cpp file and replaced -std=g++17 with -std=g++11 and applied it to a cut-down file; didn’t make any difference. So, as far I tell there’s some difference in default options specified between the two compiler versions in use in the two esp8266 package versions.

Constant expressions that evaluate to zero of int type (at least), will convert to null pointer constants. I haven’t been in the habit of using character-typed ('') zero valued constant expressions for null pointers, and I haven’t dug through the various editions of the C++ standard to see what each one has to say about them; color me unsurprised either way. But in any case, that’s is basically what’s happening here: The string object is being compared to a null pointer constant, at least when it compiles. And if that makes you go WTF, well, me too. If you follow this out, you ultimately you end up here:

unsigned char String::equals(const char *cstr) const {
    if (len() == 0)
        return (cstr == NULL || *cstr == 0);
    if (cstr == NULL)
        return buffer()[0] == 0;
    return strcmp(buffer(), cstr) == 0;
}

So, roughly speaking someArduinoString == '', where it will compile, is equivalent to someArduinoString == nullptr which is sort of the same effect as someArduinoString == "". So, what you’re seeing is not exactly an implicit form of someArduinoString == String('').

I can’t picture wanting to say someArduinoString == '' over someArduinoString.isEmpty(), but in terms of why it doesn’t work on 3.0.0, I’m still unsure. I can tell you that it will if you plant -fpermissive into platform.txt, but that doesn’t really explain it. Sometime when I’m really bored I’ll see what the language standard actually says and what versions of g++ did what under what options.

Even I worked that out my answer would still be: don’t do that.

Понравилась статья? Поделить с друзьями:
  • Cannot complete your request ошибка citrix
  • Cannot complete the device driver installation wizard как исправить
  • Cannot communicate with server error
  • Cannot bulk load because the file could not be opened operating system error code 5
  • Cannot boot from cd code 5 как исправить