Недостаток в Java для uint16_t в NDK не обрабатывается правильно? - PullRequest
0 голосов
/ 11 мая 2018

Я озадачен поведением, которое я вижу с Android NDK относительно отрицательных шорт в качестве параметров. Я сократил это до простого примера.

У меня есть следующая функция c:

void shortTest(uint16_t input)
{
    uint16_t tmp = -1;
    LogInfo("shortTest input: 0x%X\n", input); // wrapper for logging
    LogInfo("shortTest tmp: 0x%X\n", tmp);
}

Соответствующая подпись Java:

void shortTest(short input);

Функция вызывается так:

short s = -1;
MyLibrary.INSTANCE.shortTest(s);

Выход:

INFO   : 21:10:01:158 - shortTest:6158: shortTest input: 0xFFFFFFFF
INFO   : 21:10:01:158 - shortTest:6159: shortTest tmp: 0xFFFF

Такое поведение может вызвать сбои, например, при сравнении (входные данные не равны tmp). В качестве обходного пути я просто изменил функцию c, чтобы взять uint32_t и передать int. Тем не менее, я обеспокоен тем, что это кусает меня в других областях, так как я довольно часто пользуюсь uint16. Кажется, что-то заставляет тип хранения с 2 байтов до 4. Я что-то упустил? Это ошибка?

1 Ответ

0 голосов
/ 11 мая 2018

Java short подписано, так что вы как бы лжете компилятору о том, что shortTest получит.

Давайте рассмотрим последствия этого, посмотрев на следующий код C и соответствующую сборку ARM:

// Here I'm using int16_t, because that's basically what you've declared that
// you will pass to shortTest from your Java code.
void shortTest(int16_t input) {
    printf("shortTest input: 0x%X\n", input);
}

int main() {
    shortTest(-1);
}

shortTest:
    stmfd   sp!, {r4, lr}
    mov     r1, r0              @ Just pass on input as the second argument to printf
    movw    r0, #:lower16:.LC0  @ Load string address
    movt    r0, #:upper16:.LC0  @ ...
    bl      printf              @ Call printf
    ldmfd   sp!, {r4, pc}       @ Return


main:
    stmfd   sp!, {r4, lr}
    mvn     r0, #0         @ First argument = 0xFFFFFFFF
    bl      shortTest      @ Call shortTest
    mov     r0, #0         @ Value to return from main
    ldmfd   sp!, {r4, pc}  @ Return

Мой main здесь будет ваш Java-код, поэтому он передает 0xFFFFFFFF в shortTest, что хорошо, потому что всем известно, что shortTest хочет подписать короткое замыкание. Затем вы получите shortTest, который (в вашем случае) думает, что он получил неподписанную короткую позицию, но предполагает, что вызывающая сторона передала правильный тип значения, поэтому он не будет выполнять нулевое расширение.

Затем вы пытаетесь напечатать это значение, и если ваша функция ведения журнала работает как printf / sprintf, она будет неявно переводить ваш short в int, то есть будет печатать 32-битное значение (исключая ведущие нули). И 32-разрядное значение в этом случае 0xFFFFFFFF.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...