const променливите не могат да се използват в постоянен израз?

Защо този C код е незаконен в Visual Studio 2013 Ultimate?

const unsigned int x = 64;
char resultBufNative[x+1];

Това дава error C2057: expected constant expression.


Оригинален въпрос

Напълно съм объркан от този.

Съответна функция:

jstring Java_com_nabto_api_NabtoCApiWrapper_nabtoGetSessionToken(JNIEnv* env, jclass thiz, jobject sessionObj)
{
    const size_t size = 64;
    char resultBufNative[size+1];

    size_t resultLen;

    //Get the session
    nabto_handle_t session;
    session = (nabto_handle_t) (*env)->GetDirectBufferAddress(env, sessionObj);

    nabto_status_t nabtoStatus = nabtoGetSessionToken(session, resultBufNative, size, &resultLen);

    if (nabtoStatus == NABTO_OK && resultLen <= size) {
        // Terminate char array, convert to java string, free buffer and return result
        resultBufNative[resultLen] = 0;
        jstring result = (*env)->NewStringUTF(env, resultBufNative);
        //nabtoFree(resultBufNative);
        return result;
    }
    else {
        return NULL;
    }
}

Съобщение за грешка: error C2057: expected constant expression

На линия char resultBufNative[size+1];

За мен това прави съответния код като такъв:

    const size_t size = 64;
    char resultBufNative[size+1];

И очевидно const size_t + 1 не е постоянен израз.

Няма дефиниции или макроси, за които size се бърка (замяната му с xyzabc дава същата грешка). size_t се определя като typedef unsigned int __w64 size_t, когато преместя курсора на мишката над size_t в моята IDE (Visual Studio Ultimate 2013).

След C2057 очакваната постоянна грешка в израза, компилаторът дава още 2 грешки:

C24166: cannot allocate array of size 0
C2133: 'resultBufNative': unknown size

За същия ред код. Естествено, това е така, защото не знае какво е size + 1, така че става 0.

Използвайки

    constexpr const size_t size = 64;
    char resultBufNative[size+1];

Дава error C2065: 'constexpr' : undeclared identifier.

Използвайки

    const size_t size = 65;
    char resultBufNative[size];

Дава error C2057: expected constant expression.

Използвайки

    static const size_t size = 64;
    char resultBufNative[size+1];

Дава error C2057: expected constant expression.

Използвайки

    const unsigned int x = 64;
    char resultBufNative[x+1];

Дава error C2057: expected constant expression.

Предполагам, че това, което искам да направя, не се поддържа.


person Pimgd    schedule 12.11.2014    source източник
comment
Опитайте constexpr const size_t size = 64   -  person leemes    schedule 12.11.2014
comment
използвайте static const или constexpr   -  person Tony Delroy    schedule 12.11.2014
comment
@leemes constexpr const size_t size = 64 дава C2065: 'constexpr' unknown identifier   -  person Pimgd    schedule 12.11.2014
comment
Тогава вашият компилатор не е съвместим с C++11 и трябва да се задоволите с static const, както е предложено от @TonyD. О, и не се нуждаете от и двете constexpr и const.   -  person Some programmer dude    schedule 12.11.2014
comment
Използвам C - обърках два проекта. Кодът е пренесен от android NDK JNI wrapper, като всички препратки към android са премахнати.   -  person Pimgd    schedule 12.11.2014
comment
@BLUEPIXY, който работи, но изглежда ужасно зъл. Защо това работи, а const unsigned int x = 64 не?   -  person Pimgd    schedule 12.11.2014
comment
@Pimgd x не е константа, защото е променлива в C. VS2013 не поддържа VLA.   -  person BLUEPIXY    schedule 12.11.2014
comment
@BLUEPIXY това в някаква спецификация ли е някъде?   -  person Pimgd    schedule 12.11.2014
comment
@Pimgd да, VS2013 поддържа някои C99, но е C89(C90)+.   -  person BLUEPIXY    schedule 12.11.2014


Отговори (2)


В режим C89 размерът на масива трябва да бъде константа на времето за компилиране, но size не е едно. Ключовата дума const означава само за четене, а не времева константа за компилиране (това е различно в C++). Така че тук имате няколко възможности:

1) Компилирайте в режим C99, който поддържа VLA.

2) Използвайте масиви с фиксиран размер:

   char resultBufNative[64+1];

3) Използвайте

#define size 64

което по същество е същото като опция (2), с изключение на това, че препроцесорът прави тази замяна вместо вас.

4) Използвайте enum, както е предложено от bluepixy, което е времева константа за компилиране за разлика от const.

person P.P    schedule 12.11.2014
comment
Хм... как да компилирам в C99? - person Pimgd; 12.11.2014
comment
Ако използвате GCC или clang, това ще бъде: gcc -std=c99 -Wall file.c / clang -std=c99 -Wall file.c. - person P.P; 12.11.2014
comment
Иска ми се да използвам gcc =). Разглеждайки интернет и коментарите тук, изглежда, че ще трябва да използвам хакерските решения, тъй като VS няма C99. Иска ми се Visual Studio да поддържа C99. - person Pimgd; 12.11.2014
comment
@BLUEPIXY тогава ще трябва да проверя за NULL и предпочитам да не го правя. - person Pimgd; 12.11.2014
comment
@Pimgd Бих предпочел enum в C89, тъй като е едновременно константа на времето за компилиране и тип безопасен. Изобщо не е хакерско. - person P.P; 12.11.2014
comment
@BlueMoon от синтактична гледна точка разбирам гледната ви точка, но предпочитам да използвам enum за изброявания, а не неща като постоянни размери на масиви. Ще използвам това обаче. - person Pimgd; 12.11.2014
comment
VS2015 трябва да поддържа C99, но не съм сигурен как да го включа - person tofutim; 01.12.2015
comment
Можете да го включите, като компилирате като Cpp /Tp - person tofutim; 01.12.2015
comment
@tofutim Да, вече напълно поддържа C99: msdn.microsoft.com/en- us/library/hh409293.aspx Но нямам идея как да го включа. - person P.P; 01.12.2015
comment
@l3x Project / Properties / Configuration Properties / C/C++ / Advanced / Compile As / Compile as C++ Code (/TP) - person Bachor; 15.04.2016

Актуализирано решение е да се компилира като C++ с помощта на /Tp във Visual Studio 2015. Въпреки че не е перфектен, C++ компилаторът поддържа голямо подмножество от C99.

person tofutim    schedule 01.12.2015