Получение “конфликтующих типов для функции” в C, почему?

Я попробовал приведенный ниже код, так как у меня нет поддержки китайского, я не могу его протестировать.

var latinPresentation1 = "some text" ;
var latinPresentation2 = "some longer text";

Console.WriteLine(String.Format("{0,-30} {1,-10} ", latinPresentation1, "| " + 23));
Console.WriteLine(String.Format("{0,-30} {1,-10} ", latinPresentation2, "| " + 23));

Console.WriteLine("..............................................");

var chinesePresentation1 = "一些文字";
var chinesePresentation2 = "一些較長的文字";

Console.WriteLine(String.Format("{0,-30} {1,-10} ", chinesePresentation1, "| " + 23));
Console.WriteLine(String.Format("{0,-30} {1,-10} ", chinesePresentation2, "| " + 23));
69
задан fat 2 February 2017 в 15:25
поделиться

7 ответов

You are trying to call do_something before you declare it. You need to add a function prototype before your printf line:

char* do_something(char*, const char*);

Or you need to move the function definition above the printf line. You can't use a function before it is declared.

119
ответ дан 24 November 2019 в 13:42
поделиться
Они могут знать , что это означает, если это само объявление функции (или функция «прототип», подробнее об этом в ближайшее время), но если это просто вызов функции, они должны думаю, . И, к сожалению, догадки часто ошибочны.

Когда компилятор увидел ваш вызов do_something(), он посмотрел на то, как он был вызван, и пришел к выводу, что do_something() в конечном итоге будет объявлено так:

int do_something(char arg1[], char arg2[])
{
    ...
}

Почему он пришел к выводу, что ? Потому что именно так вы назвали это! (Некоторые компиляторы C могут прийти к выводу, что это было int do_something(int arg1, int arg2) или просто int do_something(...), оба из которых даже дальше от того, что вы хотите, но важно то, что независимо от того, как компилятор угадывает типы он угадывает их не так, как использует ваша фактическая функция.)

Позже, когда компилятор просматривает файл вперед, он видит ваше фактическое объявление для char *do_something(char *, char *). Это объявление функции даже не близко к объявлению, которое угадал компилятор, что означает, что строка, в которой компилятор скомпилировал вызов, была скомпилирована неправильно, и программа просто не будет работать. Таким образом, он правильно выводит ошибку, сообщающую, что ваш код не будет работать так, как написано.

Вы можете спросить: «Почему предполагается, что я возвращаю int?» Ну, он предполагает этот тип, потому что нет никакой информации об обратном: printf() может принимать в любой тип в своих переменных-аргументах, поэтому без лучшего ответа int является такой же догадкой, как и любая другая. (Многие ранние компиляторы C всегда предполагали int для каждого неопределенного типа и предполагали, что вы имели в виду ... для аргументов для каждой объявленной функции f(), а не void - поэтому многие современные стандарты кода рекомендуют всегда ставить void ] для аргументов, если на самом деле их не должно быть.)

Исправление

Существует два распространенных исправления ошибки объявления функции.

Первое решение, которое рекомендуется многими другими ответами здесь, состоит в том, чтобы поместить прототип в исходный код над местом, где функция сначала вызывается. Прототип выглядит так же, как объявление функции, но имеет точку с запятой, где тело должно быть следующим:

char *do_something(char *dest, const char *src);

Если поставить прототип первым, то компилятор знает , что функция в конечном итоге будет выполнять. похоже, так что не надо догадываться. По соглашению, программисты часто помещают прототипы в верхнюю часть файла, прямо под операторами #include, чтобы гарантировать, что они всегда будут определены до любого их потенциального использования.

Другое решение, которое также появляется в некотором реальном коде, состоит в том, чтобы просто переупорядочить ваши функции так, чтобы объявления функций всегда были перед чем-нибудь, что их вызывает! Вы можете переместить всю функцию char *do_something(char *dest, const char *src) { ... } выше первого вызова, и тогда компилятор точно будет знать, как выглядит функция, и не должен будет угадывать.

На практике большинство людей используют прототипы функций, потому что вы также можете взять прототипы функций и переместить их в файлы заголовков (.h), чтобы код в других файлах .c мог вызывать эти функции. Но любое решение работает, и многие кодовые базы используют оба.

C99 и C11

Полезно отметить, что правила немного отличаются в более новых версиях стандарта C. В более ранних версиях (C89 и K & amp; R) компилятор действительно будет угадывать типы во время вызова функции (а компиляторы K & amp; R-эры часто даже не предупреждают вас, если они ошибаются) , C99 и C11 требуют, чтобы объявление функции / прототип предшествовало первому вызову, и если это не так, это ошибка. Но многие современные компиляторы C - главным образом для обратной совместимости с более ранним кодом - только предупреждают об отсутствующем прототипе и не считают это ошибкой.

5
ответ дан Sean Werkema 24 November 2019 в 13:42
поделиться

In "classic" C language (C89/90) when you call an undeclared function, C assumes that it returns an int and also attempts to derive the types of its parameters from the types of the actual arguments (no, it doesn't assume that it has no parameters, as someone suggested before).

In your specific example the compiler would look at do_something(dest, src) call and implicitly derive a declaration for do_something. The latter would look as follows

int do_something(char *, char *)

However, later in the code you explicitly declare do_something as

char *do_something(char *, const char *)

As you can see, these declarations are different from each other. This is what the compiler doesn't like.

22
ответ дан 24 November 2019 в 13:42
поделиться

You didn't declare it before you used it.

You need something like

char *do_something(char *, const char *);

before the printf.

Example:

#include <stdio.h>
char *do_something(char *, const char *);
char dest[5];
char src[5] = "test";
int main ()
{
printf("String: %s\n", do_something(dest, src));
 return 0;
}

char *do_something(char *dest, const char *src)
{
return dest;
}

Alternatively, you can put the whole do_something function before the printf.

7
ответ дан 24 November 2019 в 13:42
поделиться

You have to declare the function before you use it. If the function name appears before its declaration, C compiler will follow certain rules and makes the declaration itself. If it is wrong, you will get that error.

You have two options: (1) define it before you use it, or (2) use forward declaration without implementation. For example:

char *do_something(char *dest, const char *src);

Note the semicolon at the end.

6
ответ дан 24 November 2019 в 13:42
поделиться

Заповедь C № 3:

K&R #3 Thou shalt always prototype your functions or else the C compiler will extract vengence. 

http://www.ee.ryerson.ca:8080/~elf/ hack / God.vs.K + R.html

4
ответ дан 24 November 2019 в 13:42
поделиться

When you don't give a prototype for the function before using it, C assumes that it takes any number of parameters and returns an int. So when you first try to use do_something, that's the type of function the compiler is looking for. Doing this should produce a warning about an "implicit function declaration".

So in your case, when you actually do declare the function later on, C doesn't allow function overloading, so it gets pissy because to it you've declared two functions with different prototypes but with the same name.

Short answer: declare the function before trying to use it.

3
ответ дан 24 November 2019 в 13:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: