Linux write с program

How to Write, Compile and Run a C Program in Ubuntu and Other Linux Distributions [Beginner’s Tip]

Last updated October 7, 2021 By Abhishek Prakash 21 Comments

How do you program in C on Linux? It is indeed very easy and consists of three simple steps.

Step 1: You write your program and save the file with a .c extension. For example, my_program.c.

Step 2: You compile the program and generate the object file using gcc compiler in a terminal like this:

Step 3: You run the generated object file to run your C program in Linux:

This was just the quick summary on how to compile and run C program in Linux. If you are new to either C or Linux, I’ll show these steps in detail so that you feel comfortable coding C program in Linux environment.

In fact, I’ll discuss how to run C programs in Linux terminal as well as in code editor.

Method 1: How to run C programs in Linux terminal

In order to run a C program in Linux, you need to have a C compiler present on your systems. The most popular compiler is gcc (GNU Compiler Collection).

You can install gcc using your distribution’s package manager. In Debian and Ubuntu-based Linux distributions, use the apt command:

Switch to directory where you have kept your C program (or provide the path) and then generate the object file by compiling the program:

Keep in mind that it is optional to provide the output object file (-o my_program). If you won’t do that, an object file named a.out will be automatically generated. But this is not good because it will be overwritten for each C program and you won’t be able to know which program the a.out object file belongs to.

Once you have your object file generated, run it to run the C program. It is already executable. Simple use it like this:

And it will display the desired output, if your program is correct. As you can see, this is not very different from running C++ programs in Linux.

Every time you make a change in your program, you have to compile it first and then run the generated object file to run the C program.

Method 2: How to run C programs in Linux using a code editor like Visual Studio Code

Not everyone is comfortable with command line and terminal and I totally understand that.

You can use a proper C/C++ IDE like Eclipse or Code Blocks but they are often too heavy programs and more suitable for large projects.

I recommend using an open source code editor like Visual Studio Code or Atom. These are basically text editors and you can install add-ons to compile and run programs directly from the graphical code editor.

I am using Visual Studio Code editor in this example. It’s a hugely popular open source code editor from Microsoft.

First thing first, install Visual Studio Code in Ubuntu from the software center. For other distributions, please check your Linux distribution’s package manager or software center. You may also check the official website for more information.

Start Visual Studio Code and open/create a project and create your C program here. I am using a sample Hello World program.

You must ensure that you have gcc compiler installed on your Linux system.

Next thing you would want is to use an extension that allows you to run the C code. Microsoft may prompt you for installing its own extension for C/C++ program but it is complicated to setup and hence I won’t recommend it.

Instead, I suggest using the Code Runner extension. It’s a no-nonsense extension and you can run C and C++ code easily without additional configuration.

Go to the Extensions tab and search for ‘Code Runner’ and install it.

Restart Visual Studio Code. Now, you should be able to run the C code by using one of the following way:

  • Using the shortcut Ctrl+Alt+N.
  • Press F1 and then select or type Run Code.
  • Right click the text editor and the click Run code from context menu.

When you run the program, it is compiled automatically and then run. You can see the output in terminal that is opened at the bottom of the editor. What could be better than this?

Читайте также:  Amd radeon 535 драйвер windows 10

Which method do you prefer?

Running a few C programs in Linux command line is okay but using a code editor is much easier and saves time. Won’t you agree?

I let you decide whichever method you want to use.

Like what you read? Please share it with others.

Источник

TechyTalk

Thoughts on Magento, PHP, Linux and open source

Linux system programming: Open file, read file and write file

This is my first article in what I’m hoping will be a series of articles on system programming for POSIX compliant operating systems with focus on Linux. Actually I’ve touched this topic a while ago when I wrote three articles about library programming on Linux (static libraries, dynamic libraries and dynamic libraries using POSIX API). In this series my goal is to go trough basics of Linux system programming from the easiest topics like open file, read file and file write to a bit more complicated things like Berkeley sockets network programming. So lets get started with environment setup and an example of program that copies source file into destination file using POSIX API system calls to demonstrate open(), read() and write() system calls on Linux operating system.

Configuring your environment

I’ll use my trustworthy Ubuntu Linux operating system but you can actually use any POSIX compliant operating system, the only difference will probably be that you will need to configure your environment differently. What we need to begin with Linux system programming is gcc compiler with related packages and POSIX related man pages. So here’s how to install this packages on Ubuntu based operating system:

Basically that’s all you need to create serious system tools for Linux operating system. Later we will probably need some more libraries but we will install them when necessary.

open(), read() and write() system calls

If you have named this code file sp_linux_copy.c and if you want to name executable file sp_linux_copy to compile this program you would probably use something like this:

Then if your source file is named source_file.txt and if you want to name the destination file destination_file.txt you would run this program like this:

Now lets go trough the code and explain tricky parts. First thing we must do is to include necessary header files. Man page of every system call tells you what header files you need to include to be able to use this system call. Second we will define constant we will use to define size of our buffer in bytes. Smaller buffer size will make our copy process longer but it will save memory. Next we open source and destination file descriptors, source with O_RDONLY to make it read only, destination with O_WRONLY | O_CREAT to make it writable and to create destination file with 0644 file system permission flags. In case of error we use perror() man 3 perror to print relatively user friendly error message.

Now we are ready to start copy process. We run read() and write() inside loop (because source file might be bigger than our buffer) to copy from one file into another. Important to notice is that write() is using number of bytes read from source file returned by read() so it would know how much to write into destination file. If number of bytes read (ret_in) and number of bytes written (ret_out) differ this indicates error so once again we use perror() to print out error description. At the end if all went well we do cleanup by closing both file descriptors and returning 0 (EXIT_SUCCESS) to indicate that program ended without errors.

That’s it for this introductory article on Linux system programming topic. In my next article I will show you few more examples on POSIX input/output and then move on to memory management related system calls.

Источник

How to Write and Run a C Program in Linux

Linux is becoming programming heaven for developers, being an open-source and free operating system. Turbo C compiler is already an old approach to compile programs so let us programmers move to Linux for a new programming environment. In this article, we will explain how to write, compile, and run a simple C program. This will serve as a basis for you to move to more complicated and useful C programs that you can write and execute on Linux.

We have run the steps and commands mentioned in this article on a Ubuntu 20.04 LTS system but it will work on other versions like Ubuntu 18.04 or distributions like Debian 10 in the exact same way.

We will be using the Linux command-line tool, the Terminal, in order to compile a simple C program. To open the Terminal, you can use the Ubuntu Dash or the Ctrl+Alt+T shortcut.

Step 1: Install the build-essential packages

In order to compile and execute a C program, you need to have the essential packages installed on your system. Enter the following command as root in your Linux Terminal:

Читайте также:  Замена одного linux другим

You will be asked to enter the password for root; the installation process will begin after that. Please make sure that you are connected to the internet.

Step 2: Write a simple C program

After installing the essential packages, let us write a simple C program.

Open Ubuntu’s graphical Text Editor and write or copy the following sample program into it:

Then save the file with .c extension. In this example, I am naming my C program as sampleProgram.c

Alternatively, you can write the C program through the Terminal in gedit as follows:

This will create a .c file where you can write and save a program.

Step 3: Compile the C program with gcc Compiler

In your Terminal, enter the following command in order to make an executable version of the program you have written: Advertisement

Make sure your program is located in your Home folder. Otherwise, you will need to specify appropriate paths in this command.

Step 4: Run the program

The final step is to run the compiled C program. Use the following syntax to do so:

You can see how the program is executed in the above example, displaying the text we wrote to print through it.

Through this article, you have learned how to write, compile and run a simple C program in Linux. All you need is the essential packages and the right skills to make you a programming guru in Linux!

Karim Buzdar

About the Author: Karim Buzdar holds a degree in telecommunication engineering and holds several sysadmin certifications. As an IT engineer and technical author, he writes for various web sites. You can reach Karim on LinkedIn

Источник

Заметки о Unix: системный вызов write(), на самом деле, не такой уж и атомарный

Недавно я читал материал Эвана Джонса «Устойчивое хранение данных и файловые API Linux». Я полагаю, что автор этой довольно хорошей статьи ошибается, говоря о том, чего можно ожидать от команды write() (и в том виде, в каком она описана в стандарте POSIX, и на практике). Начну с цитаты из статьи:

Системный вызов write() определён в стандарте IEEE POSIX как попытка записи данных в файловый дескриптор. После успешного завершения работы write() операции чтения данных должны возвращать именно те байты, которые были до этого записаны, делая это даже в том случае, если к данным обращаются из других процессов или потоков (вот соответствующий раздел стандарта POSIX). Здесь, в разделе, посвящённом взаимодействию потоков с обычными файловыми операциями, имеется примечание, в котором говорится, что если каждый из двух потоков вызывает эти функции, то каждый вызов должен видеть либо все обозначенные последствия, к которым приводит выполнение другого вызова, либо не видеть вообще никаких последствий. Это позволяет сделать вывод о том, что все файловые операции ввода/вывода должны удерживать блокировку ресурса, с которым работают.

Означает ли это, что операция write() является атомарной? С технической точки зрения — да. Операции чтения данных должны возвращать либо всё, либо ничего из того, что было записано с помощью write(). […].

К сожалению, то, что операции записи, в целом, атомарны — это не то, что говорится в стандарте POSIX, и даже если именно это и попытались выразить авторы стандарта — весьма вероятно то, что ни одна версия Unix этому стандарту не соответствует, и то, что ни одна из них не даёт нам полностью атомарных команд записи данных. Прежде всего, то, что в стандарте POSIX чётко сказано об атомарности, применяется лишь в двух ситуациях: когда что-то пишется в конвейер или в FIFO, или когда речь идёт о нескольких потоках одного и того же процесса, выполняющих некие действия. А то, что стандарт POSIX говорит об операциях записи, смешанных с операциями чтения, имеет гораздо более ограниченную область применения. Позвольте мне процитировать стандарт (выделение — моё):

После того как произошёл успешный возврат из операции записи (write()) в обычный файл:

  • Любая успешная операция чтения (read()) данных из каждой байтовой позиции файла, которая была модифицирована этой операцией записи, должна возвращать данные, установленные для этой позиции командой write() до тех пор, пока данные в таких позициях не будут снова модифицированы.

Это не требует какого-то особого поведения от команд чтения данных из файла, запущенных другим процессом до возврата из команды записи (включая те, которые начались до начала работы write() ). Если выполнить подобную команду read() , POSIX позволяет этой команде вовсе не прочитать данные, записываемые write() , прочитать лишь некоторую часть этих данных, или прочитать их все. Подобная команда read() (теоретически) является атомарной в том случае, если её вызывают из другого потока того же самого процесса. При таком подходе, определённо, не реализуется обычная, привычная всем, атомарная схема работы, когда либо видны все результаты работы некоей команды, либо результаты её работы не видны вовсе. Так как разрешено кросс-процессное выполнение команды read() во время выполнения команды write() , выполнение команды чтения может привести к возврату частичного результата работы команды записи. Мы не назвали бы «атомарной» SQL-базу данных, которая позволяет прочитать результаты незавершённой транзакции. Но именно это стандарт POSIX позволяет команде write() , с помощью которой выполняется запись в файлы.

Читайте также:  Директ 9 для windows 32 бит

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

Если подумать о том, что потребуется для реализации атомарных операций записи в файлы в многопроцессной среде, то сложившаяся ситуация не должна выглядеть удивительной. Так как Unix-программы не ожидают коротких сеансов записи в файлы, мы не можем упростить проблему, установив лимит размера данных, запись которых необходимо выполнять атомарно, а потом ограничив write() этим размером. Пользователь может запросить у системы запись мегабайтов или даже гигабайтов данных в одном вызове write() и эта операция должна быть атомарной. Во внутренний буфер ядра придётся собирать слишком много данных, а затем придётся менять видимое состояние соответствующего раздела файла, укладывая всё это в одно действие. Вместо этого подобное, вероятно, потребует блокировки некоего диапазона байтов, где write() и read() блокируют друг друга при перекрытии захваченных ими диапазонов. А это означает, что придётся выполнять очень много блокировок, так как в этом процессе придётся принимать участие каждой операции write() и каждой операции read() .

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

Но блокировать файлы лишь при выполнении команды read() в современных Unix-системах недостаточно, так как многие программы, на самом деле, читают данные, используя отображение файлов на память с помощью системного вызова mmap() . Если действительно требуется, чтобы операция write() была бы атомарной, нужно блокировать и операции чтения данных из памяти при выполнении команды записи. А это требует довольно-таки ресурсозатратных манипуляций с таблицей страниц. Если заботиться ещё и о mmap() , то возникнет одна проблема, которая заключается в том, что когда чтение осуществляется через отображение файла на память, команда write() не обязательно будет атомарной даже на уровне отдельных страниц памяти. Тот, кто читает данные из памяти, на которую отображается файл, может столкнуться со страницей, находящейся в процессе копирования в неё байтов, записанных с помощью write() .

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

Помимо проблем с производительностью тут наблюдаются и проблемы со справедливостью распределения системных ресурсов. Если команда write() является, по отношению к команде read() , атомарной, это значит, что длительная операция write() может остановить другую команду на значительное время. Пользователям не нравятся медленные и откладываемые на какое-то время операции read() и write() . Подобное, кроме того, даст удобный инструмент для DoS-атак путём записи данных в файлы, открываемые для чтения. Для этого достаточно снова и снова запрашивать у системы выполнение операции над всем файлом за один заход (или над таким его фрагментом, над которым можно выполнить нужную операцию).

Правда, большая часть затрат системных ресурсов происходит из-за того, что мы рассуждаем о кросс-процессных атомарных операциях записи, так как это значит, что действия по выполнению блокировок должно выполнять ядро. Кросс-поточная атомарная операция write() может быть реализована полностью на уровне пользователя, в пределах отдельного процесса (при условии, что библиотека C перехватывает операции read() и write() при работе в многопоточном режиме). В большинстве случаев можно обойтись какой-нибудь простой системой блокировки всего файла, хотя тем, кто работает с базами данных, это, вероятно, не понравится. Вопросы справедливости распределения системных ресурсов и задержки операций из-за блокировок при работе в пределах одного процесса теряют остроту, так как единственным, кому это повредит, будет тот, кто запустил соответствующий процесс.

(Большинство программ не выполняют операции read() и write() над одним и тем же файлом в одно и то же время из двух потоков.)

P.S. Обратите внимание на то, что даже операции записи в конвейеры и в FIFO являются атомарными только если объём записываемых данных достаточно мал. Запись больших объёмов данных, очевидно, не должна быть атомарной (и в реальных Unix-системах она таковой обычно и не является). Если бы стандарт POSIX требовал бы атомарности при записи ограниченных объёмов данных в конвейеры, и при этом указывал бы на то, что запись любых объёмов данных в файлы так же должна быть атомарной, это выглядело бы довольно-таки необычно.

P.P.S. Я с осторожностью относился бы к принятию как данности того, что в некоем варианте Unix, в многопоточной среде, полностью реализованы атомарные операции read() и write() . Возможно, я настроен скептически, но я бы сначала это как следует проверил. Всё это похоже на излишне прихотливые требования POSIX, на которые разработчики систем закрывают глаза во имя простоты и высокой производительности своих решений.

Приходилось ли вам сталкиваться с проблемами, вызванными одновременным выполнением записи в файл и чтения из него?

Источник

Оцените статью