0

After a hiatus of several years working with JavaScript, Java and other Internet related software I've been looking again at C and C++. I've downloaded some C code from GitHub at the link:

https://github.com/rvong/png-debugger

and got the compiled test code PNGDebugger.exe in the Debug folder to scan through the image file example.png in the test folder and the generate output as given in README.md. I also tried PNGDebugger.exe on a PNG file that I generated, and apparently it worked again without any problems.

After this I installed the free Visual Studio Community version 2019 on my Windows 10 platform, then installed C++ and its various dependencies. With that done I opened an empty C++ console project and copied over the .h and .c files from GitHub. Incidentally, to invoke the C compiler as opposed to the C++ compiler you just make sure that any files with the .cpp extension are changed to .c.

Anyway, Visual Studio flags an error for line 117 of the file readPNG.c downloaded from the link:

https://github.com/rvong/png-debugger/blob/master/readPNG.c

Lines 116 and 117 are:

int crcLen = LEN_CKTYPE + length;
unsigned char crcInput[crcLen];

and by mousing over line 117 the error is "Expression must have a constant value". This and other errors are generated by line 117 when I try and build the application. The rest of the code looks OK.

LEN_CKTYPE has a value of 4 as given in a #define in the file constants.h, and length is defined as long at the beginning of the while loop near the beginning of the function void processPNG(...) in the readPNG.c file.

How is this problem fixed, and how is it that the original code compiled successfully? Perhaps an older version of Visual Studio was used which didn't have a problem.

csharp
  • 464
  • 2
  • 10
  • 19
  • That error makes sense in C++, but not in C. So it looks like VS is compiling the file in C++ mode. Double check that file is compiled with C: right click the file in solution explorer - properties – bolov Jul 31 '20 at 23:48
  • And it looks like the original code was build with Eclipse + mingw. But that shouldn't matter. It should compile with any C compiler – bolov Jul 31 '20 at 23:52
  • line 116: `int crcLen = LEN_CKTYPE + length;` is a variable, even in C. And so line 117: crcLen is not constant at compile time. make it `const static` and compile again. or solve it with malloc and don't forget to free it later and change it to pointer of int and so on... – Ol Sen Aug 01 '20 at 00:15
  • Thanks for the various suggestions, I right clicked on readPNG.c in the Solution Explorer and tried out various options with Properties, in particular Code Generation and Language, but changing the defaults to other options didn't solve the problem. Also attempts to change int crcLen to const static int crcLen didn't work, nor declaring const int lenCktype = LEN_CKTYPE at the top of the function, then using lenCktype in line 116. – csharp Aug 01 '20 at 01:35
  • If all else fails, what is the easiest way of using malloc? It's been a number of years since I last had anything to do with C. Incidentally, the C rather than the C++ compiler is invoked. This can be checked by trying to add a class to the code, as Visual Studio flags this as an error. – csharp Aug 01 '20 at 01:39
  • Microsoft's C compiler doesn't support C99 variable length arrays like that one. – Shawn Aug 01 '20 at 02:13

1 Answers1

0

I've made a number of changes to the code so that it now compiles without any errors, and tested it out on a couple of PNG files, which gave the same output as the original compiled code downloaded from GitHub. I made three changes as follows:

1 - In processPNG the lines:

   int crcLen = LEN_CKTYPE + length;
   unsigned char crcInput[crcLen];

which gave an error were replaced by:

  char* crcResult;
  int crcLen = LEN_CKTYPE + length;
  unsigned char* crcInput = malloc(crcLen * sizeof(char));
  if (crcInput == NULL) {
    crcResult = "Failed to allocate memory for crcInput";
  } else {
    ....
  }
  free(crcInput);

as advised by Ol Sten. The original code following the crcInput declaration is put in the else block, followed by freeing up the memory. However, I don't know what happens if you call free() after malloc() failed, could someone advise me on this?

Also it may be more efficient to call malloc() on the first iteration of the while loop, then subsequently call realloc(), and move free() outside the while loop right at the end of the function, but this will involve a few more lines of code.

2 - Visual Studio also complained about using the fopen function, so in readPNG I replaced these lines:

FILE* file = fopen(path, "rb");
if (file == NULL) { printf("error: could not open file. (%s)", path); return; }

by these:

#include <errno.h>
....
FILE* file;
errno_t err;
if ((err = fopen_s(&file, path, "rb")) != 0) {
    printf("error: could not open file. (%s)", path); return;
}

3 - Also in helperFuncts.h, in the loop in function long getNum(unsigned char* a, int start, int size) this produces a warning due to different types, i.e i is unsigned long but start is int:

for (unsigned long i = start; i < start + size; i++) {
  ....
}

This was easily fixed by making start an unsigned long. With these changes made no errors were generated during the compilation or execution.

It thus appears that the C compiler used by Visual Studio 2019 is more rigorous than other C compilers, and possibly earlier versions of Visual Studio, and appears to incorporate some parts of the C++ compiler. However, it is not the C++ compiler, because attempts to add specific C++ code such as classes, generate errors. Any comments about this?

csharp
  • 464
  • 2
  • 10
  • 19
  • When you say free after malloc failed you mean free(NULL), which is perfectly fine and does nothing. – Daniel Aug 02 '20 at 23:21
  • Actually I'm using free(crcInput), where crcInput is a pointer to a string of chars. Based on https://stackoverflow.com/questions/6084218/is-it-good-practice-to-free-a-null-pointer-in-c if crcInput is NULL, then indeed nothing happens. However, if I specifically execute free(NULL) then also nothing happens, but the memory allocated by crcInput is presumably not freed, so free(NULL) itself is useless. – csharp Aug 03 '20 at 01:51